[AtCoder2272] Xor Sum

題目

原題地址c++

解說

本身選的分享題本身看了半天不會
大體題意就是給出正整數\(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\)循環就隨意了。
大功告成!可是好像只觀察出了規律沒證實……
看了半天仍是不會證實……白嫖一個吧……spa

其實在本質上看的二進制操做也比較好理解,要獲得小於等於\(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\)的狀況。code

代碼

#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;
}

幸甚至哉,歌以詠志。遞歸

相關文章
相關標籤/搜索