题目大意
小A和小B在玩石头剪刀布,他们每个人写出一个序列。
小A写出了n个数。
小B写出了m个数。
其中0代表石头,1代表剪刀,2代表布
0>1,1>2,2>0。
他们总共进行k轮,第一轮选择第一个数字,后面每一轮两个人都选择序列的下一个数进行比赛(序列结尾的下一个位置在序列开头)。
问小A和小B每人赢了几局。
瞎做
例如我们现在统计A赢了几局。
假如Ai和Bj打,那么下一次轮到Ai时,B的位置会往后位移n。
因此在B序列形成了若干个环。
枚举每个位置i,看看它赢了多少次,假设一共有p局。
若其对应位置形成的环长度为k,且(p-i+1)/(k*n)=l……r
那么首先有l*(Ai赢了这个环多少次)的答案贡献。
对于剩余r的部分,如果把环展开来,则对应了环上一个长度为(r-1)/n+1的循环区间,前缀和统计赢了多少次。
把上述过程做两次即可。
#include<cstdio>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=500000+10;
int next[maxn],a[maxn],b[maxn],cnt[maxn][3],len[maxn],belong[maxn],sum[maxn][3],id[maxn];
map<int,int> wz[maxn];
int i,j,k,t,wdc,mi,mx,n,m,top,tot;
ll p,ans,l,r;
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void work(){
fo(i,1,m){
next[i]=(i+n)%m;
if (!next[i]) next[i]=m;
}
top=0;
fo(i,1,m) belong[i]=id[i]=0;
fo(i,1,m)
if (!belong[i]){
++top;
cnt[top][0]=cnt[top][1]=cnt[top][2]=0;
len[top]=0;
j=i;k=0;
while (!belong[j]){
belong[j]=top;
cnt[top][b[j]]++;
id[j]=++len[top];
wz[top][id[j]]=j;
sum[j][0]=sum[k][0];sum[j][1]=sum[k][1];sum[j][2]=sum[k][2];
sum[j][b[j]]++;
k=j;
j=next[j];
}
}
j=1;
mx=0;
fo(i,1,n){
if (!p) break;
k=len[belong[j]];
l=p/((ll)k*n);
r=p%((ll)k*n);
ans+=(ll)l*cnt[belong[j]][(a[i]+1)%3];
if (r){
t=j;
mi=(r-1)/n+1;
if (id[t]+mi-1<=k){
wdc=wz[belong[j]][id[t]+mi-1];
ans+=(ll)(sum[wdc][(a[i]+1)%3]-sum[t][(a[i]+1)%3]);
if (b[t]==(a[i]+1)%3) ans++;
}
else{
wdc=wz[belong[j]][(id[t]+mi-2)%k+1];
ans+=(ll)sum[wdc][(a[i]+1)%3];
wdc=wz[belong[j]][k];
ans+=(ll)(sum[wdc][(a[i]+1)%3]-sum[t][(a[i]+1)%3]);
if (b[t]==(a[i]+1)%3) ans++;
}
}
j++;
if (j>m) j=1;
p--;
mx++;
}
p+=mx;
fo(i,1,top) wz[i].clear();
}
int main(){
n=read();m=read();scanf("%lld",&p);
fo(i,1,n) a[i]=read();
fo(i,1,m) b[i]=read();
work();
printf("%lld ",ans);
fo(i,1,max(n,m)) swap(a[i],b[i]);
swap(n,m);
ans=0;
work();
printf("%lld\n",ans);
}