校内模拟赛(二)(9.12)

题1:非负的部分和 
【题目描述】 
  WZK最近收到了一个任务。 
给出一个 n 个数的序列,为 A0,A1,,,,An-1,循环移动 k 位之后,这
成了 Ak,Ak+1,,,,An-1,A0,A1,,,,Ak-1。一种优秀的循环移动是,
前i(1<=i<=n)项和都满足不小于零。请给出这个序列优秀循环移动的个数。 
  这道题目当然是很简单啦,但是 WZK忙着吃小浣熊干脆面,手上油油的写不
是就麻烦你啦!如果能做到满分,他就会考虑请你吃一包哦~ 
 
【输入格式】 
  第一行一个整数 n(1 <= n <= 10^6),表示有n个数。 
  第二行n个整数,Ai(-1000 <= Ai <= 1000)表示给出的第i 个数。 
 
【输出格式】 
  一行一个整数,表示优秀循环移动的个数。 
 
【样例输入】 
3 
2 2 1 
 
【样例输出】 
View Code

很神奇的题,直接单调队列维护就好了

手推很容易出公式的,qwq

#include<bits/stdc++.h>
#define I inline
using namespace std;
const int N=1e6+7;
int a[N],s[N*2],n,ans;
deque<int> que;
I int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    n=read();
    for (int i=1;i<=n;i++)
    s[i]=s[i-1]+read(),s[i+n]=s[i];
    for (int i=n+1;i<=2*n;i++) s[i]+=s[n];
    que.push_back(1);
    for (int i=1;i<n;i++)
    {
        while (!que.empty()&&s[que.back()]>s[i]) que.pop_back();
        que.push_back(i);
    }
    for (int i=n;i<2*n;i++)
    {
        if (que.front()<=i-n) que.pop_front();
        while (!que.empty()&&s[que.back()]>s[i]) que.pop_back();
        que.push_back(i);
        if (s[que.front()]-s[i-n]>=0) ans++;
    }
    printf("%d
",ans);
    return 0;
}
View Code

第二道题我到现在都没有想出来正解

所以就咕咕咕了,有大佬想吊打我的,请随手切了教教我呗

题面如下:

【题目描述】 
  WZK在众人的鄙视之下,终于下定决心要减肥了。他发现网球选手的身材都很好,于是
找来好友YJC来进行网球比赛。 
 
  下面还是简单的讲述一下网球比赛的计分规则: 
局:一局比赛只有一名选手发球,率先赢得至少 4分并多出对手至少2分的选手赢得一
局。网球每局的记分方法十分特殊,从 03 分分别为“零”(love)、“十五”(fifteen)、
“三十”(thirty)和“四十”(forty)。记分时,发球手的得分在前。因此“30 比0”的意
思是,发球手赢得 2 分,而接球手还未得分。当双方选手都得到了 3 分时,一般叫“平局”
(deuce)而非“40比 40”。在出现平局后一名球手再得一分,被称为“占先”(advantage),
而不再记分。如果在占先的情况下失去一分,就再度回到平局;如占先后再得一分,就赢得一局。 
盘:当一名选手至少赢得4局并且至少比对手领先两局时,就赢得了这一盘。当双方赢
得的局数为6-6时,则进入“抢七”。 
抢七:抢七局中,记分采用正常的数列表示,率先获得 7分并领先对手至少2 分的选手
获胜。 
比赛:赢得两盘的选手即赢得了比赛。 
 
虽然他们感情很好,WZK还是想要赢得比赛。WZK潜心研究了自己赢得1 分的概率,WZK
想知道他赢得1局、1 盘和整个比赛的概率是多少。(要是太低咱就不比了是吧) 
 
【输入格式】 
  多组测试数据。 
  每一组测试数据,输入一行 1个实数 p(0 <= p <= 1),表示WZK赢得1分的概率。 
 【输出格式】 
  对于每一组数据,输出一行 311 位小数,分别表示 WZK 赢得 1 局、1 盘和整个比赛
的概率。 
 
【样例输入】 
0.5 
0.3 
0.7 
 
【样例输出】 
0.50000000000 0.50000000000 0.50000000000 
0.09921103448 0.00016770463 0.00000008437 
0.90078896552 0.99983229537 0.99999991563 
View Code

第三道题,我最初想的是这排列出来之后没法搞啊,有50!的排列数

结果,之后我很神奇的发现,我们其实有个最优策略:

我们定当前方向为180度的方向,直接将forward用完,之后再在剩下的所有可转角度中,选择一个距离360度最近的角度

再把backward用完,之后剩下的操作一次转完就够了呀qwq,最后ans即余弦定理算出即可

题3:WZK 的豪华游轮 
【题目描述】 
WZK 经过一辈子的奋斗,终于攒够钱买了一条豪华游轮(其实就是条小木船),这种船
可以执行4种指令: 
    right X : 其中 X是一个1到719的整数,这个命令使得船顺时针转动X 度。 
    left X : 其中X 是一个1到719的整数,这个命令使得船逆时针转动X度。 
    forward X : 其中 X是一个整数(1到 1000),使得船向正前方前进X 的距离。 
    backward X : 其中X是一个整数(1到 1000),使得船向正后方前进X 的距离。 
WZK随意的写出了 n个命令,他想找出一个种排列命令的方法,使得船最终到达的位置
距离起点尽可能的远。 
【输入格式】 
第一行一个整数 n(1 <= n <= 50),WZK给出的命令数。 
接下来n行,每行表示一个命令。 
 
【输出格式】 
一个浮点数,能够走的最远的距离,四舍五入到 6位小数。 
 
【样例输入】 
3 
forward 100 
backward 100 
left 90 
 
【样例输出】
141.421356 
View Code

上面是题面,下面奉上我丑陋的代码:

#include<bits/stdc++.h>
#define db double
using namespace std;
const int N=101;
const double PI=acos(-1.0);
bool dp[51][N<<4];
int fro,bac,lf,rg;
struct node
{
    int d,opt;
} t[N];
int cnt,n;
double sqr(double x)
{
    return x*x;
}
int main()
{
    freopen("ship.in","r",stdin);
    freopen("ship.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
    char s[N];scanf("%s",s);
    int x;scanf("%d",&x);
    if (s[0]=='f') fro+=x;    
    if (s[0]=='b') bac+=x;
    if (s[0]=='l') t[++cnt].d=x,t[cnt].opt=0;
    if (s[0]=='r') t[++cnt].d=x,t[cnt].opt=1;
    }
    dp[0][180]=true;
    for (int i=1;i<=cnt;i++)
    {
        for (int j=0;j<360;j++)
        {
        if (dp[i-1][j])
        {    
            dp[i][j]=dp[i-1][j];
            if (t[i].opt) dp[i][(j-t[i].d+720)%360]=true;
            else dp[i][(j+t[i].d)%360]=true;
            }    
        }
    }
    int a=0,b=0,p;
    for (int i=0;i<=180;i++) if (dp[cnt][i]) {a=i;break;}
    for (int i=359;i>=180;i--) if (dp[cnt][i]) {b=i;break;}
    p=min(a,360-b);p=180-p;
    double fp=cos(p/180.0*PI);
    double ans=sqrt(sqr((db)fro)+sqr((db)bac)-2*fro*bac*fp);
    printf("%.6lf
",ans);
    return 0;
}
View Code

中间要做一次01 bool型背包,相信大家都会做得对吧qwq

慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/11541214.html