您的位置:首页 > 其它

【hdu】3430 Shuffling【中国剩余定理】

2016-07-11 13:25 274 查看
题意:给出n张牌,标号为1-n,然后给出两个序列,序列1表示序列1,2,3,4……,n洗一次牌后到达的,序列2表示目标序列,问初始序列按序列1的洗牌方式洗几次能到达序列2的情况,如果不能到达输出-1

题解:在初始序列和序列1的变换中找出1能变到那些牌,这些牌构成一个集合,这些集合中的牌必然是能够相互到达的,然后在序列2中也找出这样一个集合,集合中这些元素的相互顺序是要一样的,这就是判断能否达到,然后这样可以列出几个线性同余方程组,用中国剩余定理求解即可,oj上数据比较弱

#include<cstdio>
#include<cstring>
using namespace std;
#define ll __int64
const int N=530;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){
x=1;
y=0;
return a;
}
ll gcd=exgcd(b,a%b,x,y);
ll tmp=x;
x=y;
y=tmp-a/b*x;
return gcd;
}
ll zhongguo(ll m,int a[],int b[])
{
ll a1,a2,b1,b2,x,y;
ll flag=0;
a1=a[0];b1=b[0];
for(ll i=1;i<m;i++){
a2=a[i];b2=b[i];
ll gcd=exgcd(a1,a2,x,y);
if((b2-b1)%gcd){
flag=1;
break;
}
ll t=a2/gcd;
x=(x*(b2-b1))/gcd;
x=(x%t+t)%t;
b1=a1*x+b1;
a1=(a1*a2)/gcd;
b1=(b1%a1+a1)%a1;
}
if(flag==1)return -1;
return b1;
}
int main()
{//freopen("C:\\Users\\Administrator\\Desktop\\input.txt","r",stdin);
int n,vis
,x
,y
,a
,b
,c
,u,cnt,flag,cnt1;
while(scanf("%d",&n)&&n){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
memset(vis,0,sizeof(vis));
flag=0;cnt=0;
for(int i=1;i<=n;i++)if(!vis[i]){
u=i;cnt1=0;
while(!vis[u]){
vis[u]=1;
c[cnt1++]=u;
u=a[u];
}
int pos=0;
while(pos<cnt1&&b[i]!=c[pos])pos++;
if(pos==cnt1){flag=1;break;}
x[cnt]=cnt1;y[cnt++]=pos;
u=a[i];
while(u!=i){
if(b[u]!=c[(++pos)%cnt1]){flag=1;break;}
u=a[u];
}
if(flag==1)break;
}
if(flag==1){printf("-1\n");continue;}
printf("%I64d\n",zhongguo(cnt,x,y));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: