Bzoj 1087: [SCOI2005]互不侵犯King

Bzoj 1087: [SCOI2005]互不侵犯King

题链
今天下午没有事情,学习了一下\(状压DP\).感觉非常nice.
\(f[i][j][k]\)表示到达第\(i\)\(j\)个状态使用了\(k\)的国王的方案数.
首先筛出行合法的状态.然后二进制操作.
我这里设\(a\)为合法状态.
转移的时候.
\(a[i] \& a[j]\)\((a[i] << 1) \& a[j]\)\(( (a[j] << 1) \& a[i] )\)
如果这三者等于\(0\)的话,状态可以转移.

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxN = 16 + 7;
const int max_num = 1030;

int n,k;
long long f[18][2000][100];

int cnt ;
int Q[40];
int a[2000];
int tal[2000];

void work() {
    int num = 0,tmp = 0;
    for(int i = 0;i < n;++ i) {
        if(Q[i]) num += (1 << i),tmp ++ ;
    }
    cnt ++;	
    a[cnt] = num;
    tal[cnt] = tmp;
    return ;
}

void dfs(int tot) {
    if(tot == n) {work();return ;}
    dfs(tot + 1);
    if(!Q[tot - 1]) {
        Q[tot] = 1;
        dfs(tot + 1);
    }
    Q[tot] = 0;
    return ;
}

int main()
{
    scanf("%d%d",&n,&k);
    	Q[0] = 1;
        dfs(1);
        Q[0] = 0;
        dfs(1);
        for(int i = 1;i <= cnt;++ i) f[1][i][tal[i]] = 1;
        for(int i = 2;i <= n;++ i) {
            for(int j = 1;j <= cnt;++ j) {
                for(int l = 1;l <= cnt;++ l) {
                    if(a[j] & a[l]) continue;
                    if((a[j] << 1) & a[l]) continue;
                    if((a[j] >> 1) & a[l]) continue;
                    for(int gs = tal[j];gs <= k;++ gs) {
                        f[i][j][gs] += f[i - 1][l][gs - tal[j]];
                    }
                }
            }
        }
        long long ans = 0;
        for(int i = 1;i <= cnt;++ i) {
            ans += (long long)f[n][i][k];
        }
    printf("%lld",ans);	
    return 0;
} 

我们发现\(n,m\)特别小.显然是可以搜索暴力枚举出来的.

#include <iostream>
#include <cstdio>
const int maxN = 100;

long long ans[maxN][maxN] = {
{0},
{1,1},
{1,4,0,0,0},
{1,9,16,8,1,0,0,0,0,0},
{1,16,78,140,79,0,0,0,0,0,0,0,0,0,0,0,0},
{1,25,228,964,1987,1974,978,242,27,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,36,520,3920,16834,42368,62266,51504,21792,3600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,49,1020,11860,85275,397014,1220298,2484382,3324193,2882737,1601292,569818,129657,18389,1520,64,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,64,1806,29708,317471,2326320,12033330,44601420,119138166,229095676,314949564,305560392,204883338,91802548,25952226,4142000,281571,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,81,2968,65240,962089,10087628,77784658,450193818,1979541332,6655170642,17143061738,33787564116,50734210126,57647295377,49138545860,31122500764,14518795348,4959383037,1237072414,224463798,29275410,2673322,163088,6150,125,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};

int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    printf("%lld",ans[n][m]);
    return 0;
}
posted @ 2018-10-04 21:26  Rlif  阅读(103)  评论(0编辑  收藏  举报