Dyslexic Gollum

题意:

求长度是n的二进制串中,不含长度大于等于k的回文串的个数

分析:

dp[i][j][k]表示长度i,后11位状态是j不含长度大于等于k的回文串的个数(因为k最大是10,所把后11位状态压缩,dp[i][j][k]=dp[i-1][j>>1][k]+dp[i-1][j>>1|(1<<10)][k],i-1的低11位就是i的高11位以此转移过来)

预处理出来[1,1<<11)中的最大回文串长度,方便统计。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
int num[410][15],b[15][1<<11],dp[410][1<<11][15];
int pos[15];
void init(){
    b[1][0]=b[1][1]=1;
    for(int i=2;i<=11;++i){
        int cas=(1<<i);
        for(int j=0;j<cas;++j){
                int q=j;
            for(int k=1;k<=i;++k)
            {
                pos[k]=q%2;
                q/=2;
            }
            int f=1;
            for(int k=1;k<=i/2;++k)
                if(pos[k]!=pos[i-k+1]){
                    f=0;
                    break;
                }
            if(f)
                b[i][j]=i;
            else{
                b[i][j]=max(b[i-1][j&((1<<(i-1))-1)],b[i-1][j>>1]);
            }

        }
    }
    for(int i=1;i<=11;++i)
    {
        int cas=(1<<i);
        for(int j=0;j<cas;++j)
            for(int k=b[i][j]+1;k<=10;++k)
        {
            if(i==11)dp[11][j][k]++;
            num[i][k]++;
        }
    }
    for(int i=12;i<=400;++i){
        for(int j=0;j<(1<<11);++j)
            for(int k=2;k<=10;++k)
        {
            if(b[11][j]>=k)
                dp[i][j][k]=0;
            else{
                dp[i][j][k]=(dp[i-1][j>>1][k]+dp[i-1][(j>>1)|(1<<10)][k])%mod;
                num[i][k]=(num[i][k]+dp[i][j][k])%mod;
            }
        }
    }
}
int main()
{
    init();
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        printf("%d\n",num[n][m]);
    }
return 0;
}

 

posted on 2015-10-25 21:09  积跬步、至千里  阅读(145)  评论(0编辑  收藏  举报

导航