这次比赛归结起来就是:连蒙带猜,坑蒙拐骗,大胆猜测。

 

a.决战网球

组织字符串信息,维护当前局和当前场的两方胜负情况,注意换行符的输出。代码是比赛时着急写的,很丑。

#include<cstdio>
#include<iostream>
using namespace std;
 
int n;
char s[1005];
int a,b,c,d;
int notfirst;
 
int main()
{
    //freopen("input.in","r",stdin);
    scanf("%d",&n);
    scanf("%s",s+1);  
    for(int i=1;i<=n;i++)
    {    
        if(s[i]=='W')a++;
        else b++;
           
        if(a==4||b==4)
        {   
            if(notfirst&&(c==0&&d==0))putchar('\n'); else notfirst=1;
            printf("%d:%d\n",a,b);
            if(a==4)c++; else if(b==4)d++;
            a=0;b=0;
            if(c==2||d==2){c=0;d=0;}
        }
    }
    return 0;
}

b.ash

如果要枚举所有的两两组合,o(n^2)的时间必定会超时,但注意到每个元素只有不到100000,于是可以开一个100000的数组记录每个数字的出现次数,然后生成200000以内的所有平方数,对于每个平方数,枚举哪两个数加起来等于它,两个数的数量相乘就是组合个数,注意两个数相等时为c(n,2).

比赛时n*(n-1)/2被写成(n+(n-1))/2死活找不出错,居然这么大的错误过了91%的数据,不可思议!最后发现是sb错误,代码同样丑。

#include<cstdio>
#include<iostream>
using namespace std;
 
long long n,a[200005];
bool ok[200005];
long long sum;
int main()
{
//  freopen("input.in","r",stdin);
    scanf("%lld",&n);
    int x;
    for(int i=1;i<=n;i++){scanf("%d",&x);a[x]++;}
    for(int i=1;i*i<=200000;i++)ok[i*i]=1;
    for(int i=200000;i>0;i--)
    {
        if(!ok[i])continue;
        for(int j=1;j<=i/2;j++)if(a[j])sum+=((long long)a[j]*a[i-j]);
        if(i%2==0)sum+=((long long)a[i/2]*(a[i/2]-1))/2-(long long)a[i/2]*a[i/2];       
    }
    printf("%lld\n",sum);
    return 0;
}

c.欣姐姐的烦恼

lcm(a,b)=a*b/gcd(a,b),玄学瞎猜,交上去试一下居然过了,真是大跌眼镜。其实吧,如果n是奇数,则(n/2,n/2+1)的gcd应该是1,这时lcm最大,若n为偶数,从n/2向两边扩展,直到找到两个数的gcd为1,大概这样想:从n/2的两边应该很快就能找到这样的两个数gcd=1,如果在距离n/2更近的位置找到了两个数但他们的gcd不是1,至少是2,则这两种的a*b相差不大,但后一种除以2,影响是比较大的,所以选前一种,找到远点的gcd=1的。嗯,确实玄学,因为我智商低。

#include<cstdio>
#include<iostream>
using namespace std;
 
int n,t;
 
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
 
int main()
{
    //freopen("input.in","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        if(n%2)
        {
            int m=n/2;
            n=m+1;
            while(gcd(m,n)!=1){m--;n++;}
            printf("%lld\n",(long long)m*n);
        }
        else
        {
            int m=n/2;
            n=m;
            while(gcd(m,n)!=1){m--;n++;}
            printf("%lld\n",(long long)m*n);
        }
    }
     
    return 0;
}

d。Morse Code

一道水题。。因为这道没ak。。但好难思考。。最后还是不理解,ascll而非ascii,还有%大数而非128,为什么大家都能想到输出ascii字符呢?真的是奇怪。。这样的编码解码如果%大数后大于127,输出什么?这样明显不完备的编码有什么意义?wa了n次,没代码。。

 

e.给qz买五饭

n*k-sigma(ai)>ai并且k>max(ai),直接出结果。

#include<cstdio>
#include<iostream>
using namespace std;
 
int n;
int a[1005];
 
int main()
{
    //freopen("input.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int maxn=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>maxn)maxn=a[i];
        sum+=a[i];  
    }
    if((int)(2.0*sum/n+1)>maxn)maxn=(int)(2.0*sum/n+1);
    printf("%d\n",maxn);
    return 0;
}

f.gjc又研究数列了!大家快跑!!

一开始带着freopen交了上去wa了一发

#include<cstdio>
#include<iostream>
using namespace std;
 
int n;
 
int main()
{
    //freopen("input.in","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        bool ok=0;
        for(int i=30;i>=0;i--)if(n&(1<<i)){if(n-(1<<i)==0){ok=1;break;}}
        if(ok)printf("Yes\n");else printf("No\n");
    }
     
    return 0;
}

g.狗哥买游戏

#include<cstdio>
#include<iostream>
using namespace std;
 
int n;
long long a,b;
int main()
{
    //freopen("input.in","r",stdin);
    scanf("%lld%lld",&a,&b);
    printf("%lld\n",(10*a+b)/111%1111);
     
    return 0;
}

h.神奇的手表

多计了多少时间与秒数无关,只须看时和分的关系即可。多的时间处理和答案输出还是有些东西的。

官方题解说把时分都换到秒里面,比较简单,感觉怪怪的。。反正只有自己的思路自己最接受。。

#include<cstdio>
#include<iostream>
using namespace std;
 
int d,h,m,s;
int main()
{
//  freopen("input.in","r",stdin);
    while(scanf("%d%d:%d:%d",&d,&h,&m,&s)!=EOF)
    {
        if(d==0&&h==0&&m==0&&s==0){printf("%d %02d:%02d:%02d\n",d,h,m,s);continue;}
        int last=0;
        last+=24*d;
        if(m>h)last+=h+1;
        else if(m<=h)last+=h;    
     
    s-=last;
    while(s<0){m--;s+=60;}
    while(m<0){m+=60;h--;}
    if(h<0){d--;h+=24;}
    printf("%d %02d:%02d:%02d\n",d,h,m,s);
    }
    return 0;
}

I: 这是一个NIm博弈裸题

前一两天刚做过2016新生杯初赛也有一道博弈的题,比这个简单,但那个基础思想很神奇,很启发,在我2016初赛那篇博文里有介绍。于是这道题我想:qz取两次,每次取完一堆,也可以只取一堆的一点儿,也就是说,qz每轮取0,1,2堆,而ksf每轮取0,1堆。

于是我就分类讨论了。n偶&&ksf先,ksf取0qz取2,ksf取1qz取1,qz必胜;

n偶&&qz先,qz先取2堆,转化为n偶&&ksf先,qz必胜;

n奇qz先,qz取1,转化为n偶ksf先,qz必胜。

n奇&&ksf先,ksf不管取0还是1都可以转化为qz必胜的情况。

不对啊。。怎么可能qz一定胜呢?有问题。想到1,1,1,1这种n偶ksf先的局面,因为每堆只有1个,所以qz每次限定死必须取2堆,ksf必须每次1堆,于是找到破绽了。

先看如果n堆每堆全为1:

qz先手:若n%3==1或2,qz胜,n%3==0,ksf胜

ksf先手:若n%3==0或2,qz胜,n%3==1,ksf胜

如果n堆仅有1堆数量非1:

qz先手:qz胜

ksf先手:n%3==2,qz胜,n%3==1或0,ksf胜

如果n堆仅有2堆数量非1:

qz先手:qz胜

ksf先手:qz胜

从2堆非1的大概有了些感觉,后面的应该qz必胜了。随便交上去试一试,!!!居然过了!

其实后面的一定可以向下转化,类似数学归纳法的思想。

#include<cstdio>
#include<iostream>
using namespace std;
 
int n,d,a[1000005];
bool ok;
int main()
{
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int sum=0;
    for(int i=1;i<=n;i++)if(a[i]==1)sum++;
    if(sum==n)
    {
        if(d==1&&n%3==0)ok=0;
        else if(d==2&&n%3==1)ok=0;
        else ok=1;
    }
    else if(sum==n-1)
    {
        if(d==1)ok=1;
        else if(d==2&&n%3==2)ok=1;
        else ok=0;
    }
    else ok=1;
     
    if(ok)puts("Yes");
    else puts("No");
     
    return 0;
}

后来看官方题解,发现开始就讨论qz必输的情况,感觉有点难以想到。

 

j.只有你不存在的世界β

维护当前遇到的最高的高度,从左到右扫一遍,就好了。

#include<cstdio>
#include<iostream>
using namespace std;
 
int n,a[1000005],d[1000005],maxn,sum;
 
int main()
{
    //freopen("input.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        if(a[i]>maxn)
        {
            d[i]=a[i]-maxn;
            maxn=a[i];
        }
    }
    for(int i=1;i<=n;i++)sum+=d[i];
    for(int i=1;i<=n;i++)
    {
        if(d[i])printf("%d %.5f\n",i,(double)d[i]/sum);
    }
     
    return 0;
}