HDOJ 6768 The Oculus (哈希) (杭电多校2020第二场1006) 题解

http://acm.hdu.edu.cn/showproblem.php?pid=6768
思路:
因为数据的范围
1 ≤ ∣ A ∣ , ∣ B ∣ ≤ 1000000. 1≤|A|,|B|≤1000000. 1A,B1000000.
2 ≤ ∣ C ∣ ≤ ∣ A ∣ + ∣ B ∣ + 1. 2≤|C|≤|A|+|B|+1. 2CA+B+1.
∑ ∣ A ∣ , ∑ ∣ B ∣ ≤ 5000000. ∑|A|,∑|B|≤5000000. A,B5000000.
给的有点大,所以我们找一个模数,这个数应该满足,在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();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值