1. 程式人生 > >【ACM-ICPC 2018 徐州賽區網路預賽 A. Hard to prepare】 DP

【ACM-ICPC 2018 徐州賽區網路預賽 A. Hard to prepare】 DP

題目連結 https://nanti.jisuanke.com/t/31453 題意 一個圓環,每個位置可以選擇2^k中任意一個數,要求相鄰位置異或不等於2k12^{k-1} 做法 考慮遞推時的做法,如果我們把這道題轉換為求一條鏈上的方案數,就很容易遞推,但是由於環有一個限定就是開頭結尾可能完全相反,導致方案數會改變,於是我們就多開一個數組存這種方案進行轉移即可。 具體為 : a[i]ia[i]表示到i位置首尾完全相同的合法鏈的方案數 b[i]ib[i]表示到i位置首尾完全相反的方案數,

c[i]ic[i]表示到i位置首尾既不完全相同也不完全相反的方案數 :我們考慮初始狀態的定義一定是: a[1]=2ka[1]=2^{k} b[1]=0b[1]=0 c[1]=0c[1]=0 我們再來考慮如何進行轉移 a[i]=a[i1]+c[i1]a[i]=a[i-1]+c[i-1] 便上一個位置若與首完全相同,那麼這一位的最後一位等於上一個位置便可以與首部完全相同 2k1上一個位置若與首完全反,則這一位置不可以與首完全相同,這樣這一位置與上一位置將會異或為2^{k}-1
上一位置若與首既不相同也不相反,那麼這一位的最後一位只需要與首完全相同即可,所以可以直接轉移
b[i]=b[i1]+c[i1]b[i]=b[i-1]+c[i-1] 便上一個位置若與首完全相反,那麼這一位的最後一位等於上一個位置便可以與首部完全相反 2k1上一個位置若與首完全同,則這一位置不可以與首完全相反,這樣這一位置與上一位置將會異或為2^{k}-1 上一位置若與首既不相同也不相反,那麼這一位的最後一位只需要與首完全相反即可,所以可以直接轉移 c[i]=(a[i1]+b[i1])(2k2)+c[i1](2k3)c[i]=(a[i-1]+b[i-1])*(2^{k}-2)+c[i-1]*(2^{k}-3) 若上一位置與首完全相同,這一位置只要不與首完全相同或者相反即可 若上一位置與首完全相反,這一位置只要不與首完全相同或者相反即可 2k1上一位置若與首既不相同也不相反,那麼這一位不僅要不能與首相同或相反,而且不能與上一位置完全相反,不然這一位置與上一位置將會異或為2^{k}-1 n便a[n]+c[n]得到遞推式之後我們遞推到第n項,稍微思考一下便知道a[n]+c[n]為最終答案 程式碼

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
const int Mod = 1e9+7;
const int maxn = 1e6+10;
ll a[maxn],b[maxn],c[maxn];
ll pow_(ll x,int y)
{
    ll ans=1;
    while(y)
    {
        if(y&1) ans=(ans*x)%Mod;
        x=(x*x)%Mod;
        y>>=1;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        a[1]=pow_(2,k);
        b[1]=0;
        c[1]=0;
        for(int i=2;i<=n;i++)
        {
            a[i]=(a[i-1]+c[i-1])%Mod;
            b[i]=(b[i-1]+c[i-1])%Mod;
            c[i]=((a[i-1]+b[i-1])*(pow_(2,k)-2+Mod)%Mod+c[i-1]*((pow_(2,k)-3+Mod)%Mod)%Mod)%Mod;
        }
        ll ans=0;
        ans=(a[n]+c[n])%Mod;
        printf("%lld\n",ans);
    }
    return 0;
}