51nod 1501 石头剪刀布威力加强版

分析:很容易想到lcm(n,m)是个周期。不妨设n<=m,设k=a*lcm+b*n+c, (0<=b*n<lcm,0<=c<n),记g=gcd(n,m),然后枚举数字num=0,1,2,枚举i=0,1,...,g-1,然后从i开始以n为步长走,直到回到原地,就得到了坐标为j*n+i的所有点走一个周期对答案的贡献。

然后就是a数组以n为步长在b数组上平移,共移b-1次,可以dp做一下,类似前面的思路,还是枚举数字,然后枚举余数,最后c次直接模拟即可,全部加起来就是答案了。

复杂度是O(n+m)的。。然而。。1015ms T了。。。改成C就变成500+ms了。。orz

  1 #include<stdio.h>
  2 #define SWAP(x,y){ll t=x;x=y;y=t;}
  3 #define ll long long
  4 const int maxn=5e5+5;
  5 int x[maxn],y[maxn];
  6 ll W[3][maxn],L[3][maxn];
  7 ll w[3][maxn]={0,0,0},l[3][maxn]={0,0,0};
  8 inline int Score(int a,int b){
  9     if(a==b)return 0;
 10     if((a+1)%3==b)return 1;
 11     return -1;
 12 }
 13 int gcd(int a,int b){
 14     return b==0?a:gcd(b,a%b);
 15 }
 16 ll n,m;
 17 ll testw,testl;
 18 void test(int k){
 19     testw=0;testl=0;
 20     for(int i=0;i<k;i++){
 21         int s0=Score(x[i%n],y[i%m]);
 22         if(s0==1)testw++;
 23         else if(s0==-1)testl++;
 24     }
 25 }
 26 int main(){
 27 //    freopen("e:\in.txt","r",stdin);
 28     int Is_exchange=0;
 29     ll k;
 30     scanf("%lld%lld%lld",&n,&m,&k);
 31     if(n>m){
 32         Is_exchange=1;
 33         for(int i=0;i<n;i++)scanf("%d",&y[i]);
 34         for(int i=0;i<m;i++)scanf("%d",&x[i]);
 35         SWAP(n,m);
 36     }else{
 37         for(int i=0;i<n;i++)scanf("%d",&x[i]);
 38         for(int i=0;i<m;i++)scanf("%d",&y[i]);
 39     }
 40 //    test(k);
 41     ll g=gcd(n,m);
 42     ll lcm=(ll)n*m/g;
 43     ll a=k/lcm;
 44     int b=(k%lcm)/n;
 45     ll c=k%n;
 46     for(int num=0;num<3;num++){
 47         for(int h=0;h<g;h++){
 48             for(int i=0;i<b;i++){
 49                 int s0=Score(num,y[(h+i*n)%m]);
 50                 if(s0==1)W[num][h]++;
 51                 else if(s0==-1)L[num][h]++;
 52             }
 53             w[num][h]=W[num][h];
 54             l[num][h]=L[num][h];
 55             for(int i=b;i<lcm/n;i++){
 56                 int s0=Score(num,y[(h+i*n)%m]);
 57                 if(s0==1)w[num][h]++;
 58                 else if(s0==-1)l[num][h]++;
 59             }
 60             int idx_last=h,idx_next=(h+b*n)%m;
 61             for(int s=(h+n)%m;s!=h;s=(s+n)%m){
 62                 W[num][s]=W[num][idx_last];
 63                 L[num][s]=L[num][idx_last];
 64                 int last=Score(num,y[idx_last]);
 65                 int next=Score(num,y[idx_next]);
 66                 if(last==1)W[num][s]--;
 67                 else if(last==-1)L[num][s]--;
 68                 if(next==1)W[num][s]++;
 69                 else if(next==-1)L[num][s]++;
 70                 idx_last=s;idx_next=(idx_next+n)%m;
 71             }
 72         }
 73     }
 74     ll answ=0,ansl=0;
 75     for(int i=0;i<n;i++){
 76         answ+=w[x[i]][i%g];
 77         ansl+=l[x[i]][i%g];
 78     }
 79     answ*=a;ansl*=a;
 80     if(b){
 81         for(int i=0;i<n;i++){
 82             answ+=W[x[i]][i];
 83             ansl+=L[x[i]][i];
 84         }
 85     }
 86     int s=((ll)b*n)%m;
 87     for(int i=0;i<c;i++){
 88         int s0=Score(x[i],y[(s+i)%m]);
 89         if(s0==1)answ++;
 90         else if(s0==-1)ansl++;
 91     }
 92     if(Is_exchange){
 93 //        printf("%lld %lld
",testl,testw);
 94         printf("%lld %lld
",ansl,answ);
 95     }else{
 96 //        printf("%lld %lld
",testw,testl);
 97         printf("%lld %lld
",answ,ansl);
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/7391-KID/p/7651959.html