南京理工大学第八届程序设计大赛题解

题目地址:https://icpc.njust.edu.cn/Contest/749/

题解:https://icpc.njust.edu.cn/gist/comzyh/a36db955-1113-4fa2-9000-2beb0bdc7201/

 

 标签题目AC / Submit
  A 偷吃糖果 614 / 1591
  B banana 1 / 479
  C count_prime 394 / 1700
  D triple 84 / 519
  E sad 2 / 49
  F sequence 355 / 1237
  G 琪露诺的算术教室 165 / 1336
  H 谁才是最强战舰! 263 / 895
  I puzzle 16 / 178
  J water1 547 / 5366

 

 

 

 

 

 

 

 

 

 

 

A.

s.去掉连续的重复的字符,然后比较是否相同。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

int main(){

    int T;
    char s[1005];
    char t[1005];
    int lens;
    int lent;

    char s2[1005];
    char t2[1005];
    int lens2;
    int lent2;

    int i;

    scanf("%d",&T);

    while(T--){

        scanf("%s",s);
        scanf("%s",t);

        lens=strlen(s);
        lent=strlen(t);

        s2[0]=s[0];
        lens2=1;
        for(i=1;i<lens;++i){
            if(s[i]!=s[i-1]){
                s2[lens2++]=s[i];
            }
        }
        s2[lens2]='\0';

        t2[0]=t[0];
        lent2=1;
        for(i=1;i<lent;++i){
            if(t[i]!=t[i-1]){
                t2[lent2++]=t[i];
            }
        }
        t2[lent2]='\0';

        if(strcmp(s2,t2)==0){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }

    }

    return 0;
}
View Code

 

C.

s.容斥原理、先对n分解质因数,分别记录每个质因数,那么所求区间内与某个质因数不互质的个数就是n/r(i),

假设r(i)是r的某个质因子 假设只有三个质因子,总的不互质的个数应该为p1+p2+p3-p1p2-p1p3-p2p3+p1p2*p3, 及容斥原理,

pi代表n/r(i),即与某个质因子不互质的数的个数,当有更多个质因子的时候,可以用状态压缩解决,二进制位上是1表示这个质因子被取进去了。

如果有奇数个1就相加,反之则相减。

#include<iostream>
#include<stdio.h>
using namespace std;

#define ll long long

ll fact[32],fNum;

void pf(ll n){

    fNum=0;
    ll i,k;
    for(i=2;i*i<=n;++i){
        if(n%i==0){
            fact[fNum++]=i;
            while(n%i==0){
                n/=i;
            }
        }
    }
    if(n>1){
        fact[fNum++]=n;
    }

}

ll solve(ll x,ll m){
    ll sum,value,cnt;

    ll i,j;

    sum=0;
    for(i=1;i<m;++i){
        value=1;
        cnt=0;
        for(j=0;j<fNum;++j){
            if(i&(1<<j)){
                value*=fact[j];
                ++cnt;
            }
        }
        if(cnt&1){
            sum=sum+x/value;
        }
        else{
            sum=sum-x/value;
        }
    }

    return x-sum;
}

int main(){

    int T;

    ll a,b,n;

    scanf("%d",&T);

    while(T--){

        scanf("%lld%lld%lld",&a,&b,&n);

        pf(n);

        printf("%lld\n",solve(b,1<<fNum)-solve(a-1,1<<fNum));
    }

    return 0;
}
View Code

 

F.略 

 

G.

s.

首先,从最后一位开始,依次k,注意进位,就可以很快的找到模拟的思路。
然后,从尾数范围10进位范围10 = 100可知。答案应该是循环的,我们用vis数组标记即可。
最后有三个错的比较多的地方:
1.B的次高位不能是0,也就说A的最高位不能是0.
2.循环什么时候结束,需要仔细斟酌一下.
3.n=0的情况,n=1的情况,和k=0的情况 请仔细考虑。

ps:这个目前似懂非懂

c.G标程

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int ans[1005];
bool vis[10][10];
int n,k;
int main(){
    int cases;
    scanf("%d",&cases);

    for (int cas=1;cas<=cases;cas++){
        scanf("%d%d",&n,&k);
        memset(ans,0,sizeof(ans));

        int top=0;
        int x=n*k %10;
        int y=n*k /10;
        y+=(ans[top]+x)/10;
        x=(ans[top]+x)%10;
        //cout<<n<<'+'<<k<<endl;
        memset(vis,false,sizeof(vis));
        bool flag=true;
        while (y!=0 || x!=n || (top>0 && ans[top-1]==0)){
            ans[top]=x;
            ans[top+1]=y;
            if (vis[ans[top]][y]){
                flag=false;
                break;
            }
            vis[ans[top]][y]=true;
            x=ans[top]*k %10;
            y=ans[top]*k /10;
            top++;
            y+=(ans[top]+x)/10;
            x=(ans[top]+x)%10;
        }
        ans[top]=x;
        ans[top+1]=y;
        top++;
        if (!flag){
            puts("-1");
            continue;
        }
        for (int i=top-1;i>=0;i--)
            printf("%d",ans[i]);
        putchar('\n');
    }
    return 0;
}
View Code

 

H.

d.这里有N堆石子,每堆石子有a[i](1<=i<=N)个,每人轮流从其中的某一堆石子中拿出任意个石子(只能在其中一堆拿,不能不拿),大和先手,谁拿出了最后一个石子,谁输。若大和必胜,输出“Yamato_Saikou!”,若依阿华必胜,输出“Meidikeji_Shijiediyi!”,若两边都无法必胜,输出“Sayonara_Konosekai!”.

s.

奇异局势,所有堆的xor和==0.

假定S是非奇异局势,T是奇异局势。
一堆中石子数量>=2,表示充裕堆, =1表示孤单堆。

S0即非奇异局势下,充裕堆为0的状态
S1即非奇异局势下,充裕堆为1的状态
S2即非奇异局势下,充裕堆>=2的状态

T0即奇异局势下,充裕堆为0的状态
T2即奇异局势下,充裕堆>=2的状态

1.奇异局势的定义可知,S能转移到T,能转移到S, T只能转移到S

2.S0必败,T0必胜

3.S1必胜,因为S1只需要转移到S0即可。

4.S2必胜,T2必败。
1)T2只能转移到S1 和 S2
2)若T2转移到S1 则T2败,若T2转移到S2,S2只需要转回到T2即可。所以S2胜,T2败。

所以:
必胜态:T0,S1,S2
必败态:S0,T2

ps:这个题当时并不会啊,只知道nim博弈是最后拿的赢,这里是最后拿的输(当时就想肯定和它差不多)。

找了下规律,那就是仅有一堆石子的时候和所有堆都只有一个石子的时候需要特别判断一下,而其它情况貌似是奇异局势必败。交了下,过了。。。

c.H标程

//必胜:T0,S1,S2
//必败:S0,T2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;

int main(){
    int cases;
    scanf("%d",&cases);
    for (int cas=1;cas<=cases;cas++){
        int n; scanf("%d",&n);
        int sum=0,ones=0;
        for (int i=1;i<=n;i++){
            int x; scanf("%d",&x);
            sum^=x;
            if (x==1) ones++;
        }
        if (sum==0){//奇异局势
            if (n-ones==0) puts("Yamato_Saikou!");//T0
            else puts("Meidikeji_Shijiediyi!");//T2
        }
        else {//非奇异局势
            if (n-ones==0){//S0
                //if (ones&1) //这个判断并没什么卵用。
                puts("Meidikeji_Shijiediyi!");
                //必定是奇数堆,非奇异局势
            }
            else puts("Yamato_Saikou!");//S1、S2
        }
    }
    return 0;
}
View Code

c2.当时交的代码

#include<iostream>
#include<stdio.h>
using namespace std;

int main(){

    int T;
    int N;
    int a[1024];
    int i;
    int sum;
    bool flag;

    scanf("%d",&T);

    while(T--){

        scanf("%d",&N);

        sum=0;
        flag=true;
        for(i=0;i<N;++i){
            scanf("%d",&a[i]);
            if(a[i]>1){
                flag=false;
            }
            sum^=a[i];

        }
        if(N==1){
            if(a[0]==1){
                printf("Meidikeji_Shijiediyi!\n");
            }
            else{
                printf("Yamato_Saikou!\n");
            }
            continue;
        }

        if(flag){// 全1
            if(N%2==1){
                printf("Meidikeji_Shijiediyi!\n");
            }
            else{
                printf("Yamato_Saikou!\n");
            }
            continue;
        }

        if(sum){
            printf("Yamato_Saikou!\n");
        }
        else{
            printf("Meidikeji_Shijiediyi!\n");
        }

    }

    return 0;
}
View Code

 

J.略

 

posted @ 2016-04-18 11:45  gongpixin  阅读(461)  评论(0编辑  收藏  举报