2018徐州网络赛-A-Hard to prepare-递推

题意就是有n个人围成圈,每个人能选择2^{k}顶不同的帽子,但是相邻两个人选择的帽子的编号不能同或为0,问有多少种方案

按照第一直觉选择帽子,第1个人有2^{k}种选择方案,第2到第n-1个人均有2^{k}-1种方案

第n个人的方案数取决于第1个和第n-1个人的帽子编号是否相同

相同时为2^{k}-1种方案,不相同时有2^{k}-2种方案,总答案是两种情况求和,到此是第一直觉

但是我们忽略了交叉的情况,即第n-1个人的那2^{k}-1种方案中包含了第n-1个人和第1个人的相同的情况和不同的情况

不同的情况是

2^{k}+2^{k}-1+2^{k}-1+...+2^{k}-1+2^{k}-2

2^{k}+2^{k}-1+2^{k}-1+...+2^{k}-1+2^{k}-1

相比少了一种,就是相同的那种,所以第n个人选择方案只有1种,相同时第n-1个人的选择和第1个人的相同,那么也是1种

2^{k}+2^{k}-1+...+2^{k}-1+1+1

到这儿我们发现第n个人确定后需要加上的方案数就是把n个人的规模减少到n-2个人的规模

所以递归即可

#include

using namespace std;

typedef long long int ll;
const ll mod=1000000000+7;
const int N=1000000+5;
int t;
ll n,k;
ll pow2[N];

ll qp(ll a,ll b)
{
    ll res=1;
    while(b){
        if(b%2) res=res*a%mod;
        a=a*a%mod;
        b/=2;
    }
    return res;
}

ll solve(ll n,ll k)
{
    if(n==1) return pow2[k];//当只有1或者2个人时候直接返回答案
    if(n==2) return pow2[k]*(pow2[k]-1)%mod;
    return pow2[k]*qp(pow2[k]-1,n-2)%mod*(pow2[k]-2)%mod+solve(n-2,k);
    //不同的情况加上相同的情况
}

int main()
{
    pow2[0]=1;
    for(int i=1;i<=1000000;i++)
        pow2[i]=pow2[i-1]*2%mod;//预处理出2的幂次
    scanf("%d",&t);
    for(int kk=1;kk<=t;kk++){
        scanf("%d%d",&n,&k);
        printf("%lld\n",solve(n,k)%mod);
    }
    return 0;
}

 

你可能感兴趣的:(other)