HL啊~你的23日游终于结束了~
由于本人实在太懒,才写了一篇题解
T4. 数字游戏
[问题描述]
HL中学茶余饭后喜欢玩游戏,一个游戏规则如下: 共两人参加游戏,若第一个人当前手中的数为w1,则下一秒他手上的数将 会变成(x1*w1 + y1) mod m;若第二个人当前手中的数为w2,则下一秒他 手上的数将会变为(x2*w2 + y2) mod m。a mod b表示a除以b的余数。
第0秒,两个人手上的数分别为h1, h2; 请求出最快在第几秒,第一个 人手上的数为a1并且同时第二个人手上的数为a2。若不可能,则输出-1。
[输入格式]
输入包含5*T+1行。 第一行为一个正整数T,表示数据组数。 对于接下来的每一组数据,第一行为一个正整数m,第二行包括两个整数 h1, a1,第三行包括两个整数x1, y1,第四行包括两个整数h2, a2,第五 行包括两个整数x2, y2。
[输出格式]
输出包含T行。 对于每一组数据,输出一行,一个整数,如题所述。
[样例输入]
2
5
4 2
1 1
0 1
2 3
1023
1 2
1 0
1 2
1 1
[样例输出]
3
-1
[数据规模与约定]
对于30%的数据:m<=1000
对于100%的数据:T<=5, h1≠a1且h2≠a2,2<=m<=10^6, 0<=h1,a2,x1,y1,h2,a2,x2,y2
突破点:
由于要模M所以数值可能出现循环!
因此可以分为以下3种情况
1.刚好同时达成目标,直接输出结果
2.任意一个在循环之外且无法同时达到,输出-1
3.目标属猪都处在循环节当中
因此,当方程k1*(循环节长度)+(进入循环的步数)+(目标位置距离循环节起始位置)=k2*(循环节长度)+(进入循环的步数)+(目标位置距离循环节起始位置),(其中k1(
再考虑一下时间复杂度,由于k1和k2都小于m,所以复杂度为O(m)
不说了,直接上代码
#include
using namespace std;
int a[1000010],b[1000010];
inline void work()
{
int m,h1,a1,h2,a2,x1,y1,x2,y2,cnt=0;
scanf("%d%d%d%d%d%d%d%d%d",&m,&h1,&a1,&x1,&y1,&h2,&a2,&x2,&y2); //输入
for (int i=0;i<1000010;i++) a[i]=b[i]=0; //清空
int w1=h1,w2=h2; //其实可以不赋值,把下面的所有w1换成h1,w2换成h2
int first1=0,first2=0,s1=0,s2=0,len1=0,len2=0;
while (len1==0||len2==0) //当
{
cnt++;
w1=(x1*w1+y1)%m;
w2=(x2*w2+y2)%m;
if (a[w1]==0) a[w1]=cnt; //如果没有出现过w1这个值则保存下来
else if (len1==0) {len1=cnt-a[w1];s1=a[w1]-1;}
//如果是第一次出现循环节则保存它的长度(len)和操作的次数(s)
if (b[w2]==0) b[w2]=cnt; //同上
else if (len2==0) {len2=cnt-b[w2];s2=b[w2]-1;}
if (w1==a1&&first1==0)first1=cnt; //第一次最终答案的位置
if (w2==a2&&first2==0)first2=cnt;
if (w1==a1&&w2==a2) //如果已经满足条件则不用继续做,直接输出结果
{
printf("%d\n",cnt);
return;
}
}
if (first1<=s1||first2<=s2||first1==0||first2==0)//如果答案在循环节之外或者根本不存在,则输出-1
{
cout<<-1;
return; //返回,执行下一个work
}
for (int i=0;i<=1000000;i++) //枚举最终答案
{
if ((len1*i+first1-first2)>0 && (len1*i+first1-first2)%len2==0)
{
printf("%d\n",len1*i+first1);
return;
}
}
cout<<-1<
欢迎dalao指出错误~