[AtCoder2272] Xor Sum

题目

原题地址

解说

自己选的分享题自己看了半天不会
大致题意就是给出正整数\(N\),求出整数对\(u\)\(v(0≤u,v≤N)\)的数目,使得存在两个非负整数\(a\)\(b\)满足\(a\ xor\ b = u\)\(a\ +\ b= v\)。这里,\(xor\)表示按位异或。 要求对答案取模\(10^9 + 7\)
先用下面的代码暴力了一遍:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	for(int i=0;i<=n;i++){
		int ans=0;
		/*cout<<i<<':'<<endl;*/
		for(int v=0;v<=i;v++){
			for(int u=0;u<=v;u++){
				for(int a=0;a<=v/2;a++){
					if(((v-a)^a)==u){
						ans++;
						/*cout<<v<<' '<<u<<endl;*/
						break;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
}

之后就像研究数列一样研究了半天,发现规律\(a_0=1,a_1=2\),之后\(a_n=a_{n/2}+a_{(n-1)/2}+a_{(n-2)/2}\)
那就按照这个思路写吧。这就是一个简单的递推了还不简单?由于\(10^{18}\)太大数组开不下,只能用\(map\)。之后就递归还是\(for\)循环就随意了。
大功告成!但是好像只观察出了规律没证明……
看了半天还是不会证明……白嫖一个吧……

其实在本质上看的二进制操作也比较好理解,要得到小于等于\(n\)的数,第一种操作是\(n/2\)即先将\(n>>1\),然后\(n<<1\),这样最后得到的数肯定不会超过\(n\),第二种操作是\(((n-1)/2)*2+((n-1)/2)\),第三种操作是\(((n-2)/2)*2+1 + ((n-2)/2)*2+1\),三种操作目的很明显,完成递推且数对数对\(a,b\)进行的操作不能使\(a+b\)出现大于\(n\)的情况。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
map<ll,ll> a; 
ll dfs(ll x){
	if(a[x]) return a[x];
	a[x]=(dfs(x/2)+dfs((x-1)/2)+dfs((x-2)/2))%mod;
	return a[x];
}
int main(){
	a[0]=1;
	a[1]=2;
	ll n;
	scanf("%lld",&n);
	ll ans=dfs(n);
	printf("%lld",ans);
	return 0;
} 

幸甚至哉,歌以咏志。

posted @ 2020-05-09 22:08  DarthVictor  阅读(155)  评论(0编辑  收藏  举报
莫挨老子!