http://acm.hdu.edu.cn/showproblem.php?pid=6768
思路:
因为数据的范围
1
≤
∣
A
∣
,
∣
B
∣
≤
1000000.
1≤|A|,|B|≤1000000.
1≤∣A∣,∣B∣≤1000000.
2
≤
∣
C
∣
≤
∣
A
∣
+
∣
B
∣
+
1.
2≤|C|≤|A|+|B|+1.
2≤∣C∣≤∣A∣+∣B∣+1.
∑
∣
A
∣
,
∑
∣
B
∣
≤
5000000.
∑|A|,∑|B|≤5000000.
∑∣A∣,∑∣B∣≤5000000.
给的有点大,所以我们找一个模数,这个数应该满足,在fb(1)到fb(2e6)的范围内的任意两个元素对这个模数都不同余,可以取264。
这么大的模数,其实直接用unsigned long long,越界了以后得到的就是模264的值。
设C=AB,C‘是C改掉一位后得到的数。
因为题目条件说过,不会出现连续的两个1,所以对于一个给定的数,不会出现同一个数值有多种不同表示的情况。
举个例子
如果给的数是5,如果没有“不允许出现两个相邻1”的情况,则011和0001都是5,因为f(4)=f(3)+f(2),一个数字可以拆成比他小的那两位。有了“不允许出现两个相邻1”这个条件就可以排除这种情况的存在
所以我们预处理出fb数组,再根据输入的ab算出a和b在模264下的值,相乘,与给的C’比较,得到差值,之后只要找这个差值在哪一位上就行辣。
#include<iostream>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define ll long long
#define ull long long
using namespace std;
const int MAXN = 2e6+6;
ull fb[MAXN];//用unsigned long long,相当于模数取了2^64
int la,lb,lc;//abc的长度
int c[MAXN];
ull aa,bb,cc;
void init(){
fb[0] = fb[1] = 1;
rep(i,2,MAXN-2) fb[i] = (fb[i-1]+fb[i-2]);
}
void solve(){
int hc,res;
aa = bb = cc = c[0] = 0;
scanf("%d",&la);
rep(i,1,la){
scanf("%d",&hc);
if(hc) aa = aa+fb[i];
}
scanf("%d",&lb);
rep(i,1,lb){
scanf("%d",&hc);
if(hc) bb = bb+fb[i];
}
scanf("%d",&lc);
rep(i,1,lc){
scanf("%d",&c[i]);
if(c[i]) cc = cc+fb[i];
}
ll dis = aa*bb-cc;//找到a*c和c'的差值
rep(i,1,lc){
if(c[i]==0&&dis==fb[i]){
res = i;
break;
}
}
printf("%d\n",res);
}
int main(){
//freopen("1006.in","r",stdin);
//freopen("outputs.txt","w",stdout);
init();
int z;
scanf("%d",&z);
while(z--) solve();
}