1. 程式人生 > >(計蒜客 31453)ACM-ICPC 2018 徐州賽區網路預賽

(計蒜客 31453)ACM-ICPC 2018 徐州賽區網路預賽

題意:n個數字排成一圈,每個數字範圍[0, \small 2^k-1],問有多少種不同的序列滿足對於所有相鄰的兩個數字,它們異或值不能為\small 2^k-1,其中第一個數字和最後一個數字也算相鄰。(0<n,k≤1e6) .

解析:①.首先易知第1個數字有2^k種選擇,第2到第n-1個數字均有2^k-1種選擇(保證與前一個異或值不能為0即可),而第n個數字即不可以和第1個數衝突,又不能和第n-1個數衝突。那麼此時的總方案數為:\small 2^k(2^k-2)(2^k-1)^{n-2}

          ②.但是發現當第1個數與第n-1個數相同時,由於第n個數字少了一個衝突所以它有2^k-1種選擇,所以上面對第n個數字少統計了一種情況,此情況方案就是當把第1個數與第n-1個數合併成一個後的長度為n-2的序列的總方案數。

程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll MAXN=1e6+5;

ll qpow(ll a, ll b)
{
	ll ans=1;
	while(b)
	{
		if(b%2)
			ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}

ll pow2[MAXN],ans[MAXN];
ll solve(int n, int m)
{
	ll ans;
	if(n==2)
		return pow2[m]*(pow2[m]-1)%mod;
	if(n==1)
		return pow2[m];
	ans = (pow2[m]*qpow(pow2[m]-1,n-2)%mod*max(pow2[m]-2,0ll)%mod+solve(n-2,m))%mod;
	return ans;
}
int main(void)
{
	int T,n,m,i;
	pow2[0]=1;
	for(i=1;i<MAXN;i++)
		pow2[i]=pow2[i-1]*2%mod;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve(n,m));
	}
	return 0;
}