【[SDOI2009]Bill的挑战】

一看题解好像全是状压DP,那么我就来补充一个容斥写法吧

乍一看,好像是水题,枚举选哪k个串,然后判断

1,如果这k个串中至少两个串某位置确定且不相同,答案显然为0
2,如果这个位置只被有且仅有一个串确定,这个位置就唯一确定了
3,否则这个位置有26种不同填数情况,统计答案时只要用乘法原理搞一下就行

但是容易想到,这样做是有问题的,以样例的第一组数据为例
我们选定串1,2,然后发现第四个位置确定是r,其他位置任选,但是无论我们构造出怎样的串,T总是可以同时匹配串3的

考虑容斥掉这些匹配到更多串的方案

首先,我们可以用上述方法求出匹配至少i个串的方案数,记为num[i]
我们需要统计恰好满足匹配i个的情况,记为ans[i]
现在问题来了,怎么容斥

考虑ans[i]与ans[j]的联系(i>j),定义保证ans[j]是恰好匹配j个串
如果再匹配到i-j个串,就是ans[j]
在i个串中,这i-j个串的选择当然就有C(i,i-j)种方案
我们有num[j],得出公式ans[j]=num[j]-∑C(i,i-j)*ans[i]
倒序处理ans数组即可

上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=1000003;
int t,n,k,num[20],len,c[20][20],ans[20];
char s[20][60];
int ksm(int x,int t)
{
    int ret=1;
    while(t)
    {
        if(t&1)
            ret=(ll)ret*x%mod;
        x=(ll)x*x%mod,t>>=1;
    }
    return ret%mod;
}
int check(int x)
{
    char tmp[60];
    for(int i=0;i<len;i++)
        tmp[i]=‘?‘;
    int rest=len;
    for(int i=0;i<n;i++)
    {
        if(x&(1<<i))
            for(int j=0;j<len;j++)
                if(!isalpha(tmp[j])&&isalpha(s[i+1][j]))
                {
                    tmp[j]=s[i+1][j];
                    rest--;
                }
                else if(isalpha(tmp[j])&&isalpha(s[i+1][j])&&tmp[j]!=s[i+1][j])
                    return 0;
    }
    return ksm(26,rest);
}
int main()
{
    for(int i=0;i<20;i++){
        c[i][0]=1;
        for(int j=1;j<=i;j++){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
    scanf("%d",&t);
    while(t--)
    {
        memset(num,0,sizeof(num));
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]);
        len=strlen(s[1]);
        int mul=1;
        if(k>n)
        {
            printf("0\n");
            continue;
        }
        for(int i=1;i<(1<<n);i++)
        {
            int cnt=0;
            for(int j=0;j<n;j++)
                if(i&(1<<j))
                    cnt++;
            if(cnt<k)
                continue;
            (num[cnt]+=check(i))%=mod;
        }
        for(int i=n;i>=k;i--)
        {
            int sum=0;
            for(int j=i+1;j<=n;j++)
                (sum+=(ll)c[j][i]*ans[j]%mod)%=mod;
            ans[i]=((num[i]-sum)%mod+mod)%mod;
        }
        printf("%d\n",(ans[k]%mod+mod)%mod);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ivanovcraft/p/9593760.html

时间: 2024-11-08 13:10:27

【[SDOI2009]Bill的挑战】的相关文章

$[SDOI2009]Bill$的挑战

\([SDOI2009]Bill\)的挑战 观察数据范围,显然是状压. 但是如果你将\(K\)加进状态中,手推一下就会发现这里要用到容斥. 但我又不是讲容斥的是吧... 所以我们尝试不将\(K\)加入状态中,而是在最后枚举恰好含有\(K\)个元素的子集个数. 我们设\(f[i][j]\)表示对于所有集合\(i\)中的元素,匹配到第\(j\)位时的方案数. 实际上我们涉及到集合的状压转移时如果考虑一个状态由哪里转移来,要枚举合法子集,显然麻烦. 我们可以考虑当前状态可转移到哪里,这样只用造出合法状

[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数据范围想做法的题,我们想到状压dp. 看了题解... ...网上给的状态是f[len][s]表示长度为len满足状态s的字符串个数. 光看状态... ...可能算重啊?! 其实... ... 状态:dp[len][s]表示长度为len,能且只能满足状态为s的字符串个数. 转移:我们先预处理出g[i]

BZOJ 1879 [Sdoi2009]Bill的挑战 ——状压DP

本来打算好好写写SDOI的DP题目,但是忒难了, 太难了,就写的这三道题仿佛是可做的. 生在弱省真是兴奋. 这题目直接状压,f[i][j]表示匹配到i,状态集合为j的方案数,然后递推即可. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k

bzoj 1879 [Sdoi2009]Bill的挑战(状压DP)

Description  Input 本题包含多组数据. 第一行:一个整数T,表示数据的个数. 对于每组数据: 第一行:两个整数,N和K(含义如题目表述). 接下来N行:每行一个字符串. Output 1 2 1 a? ?b Sample Input 50 Sample Output 对于30%的数据,T ≤ 5,M ≤ 5,字符串长度≤ 20: 对于70%的数据,T ≤ 5,M ≤ 13,字符串长度≤ 30: 对于100%的数据,T ≤ 5,M ≤ 15,字符串长度≤ 50. [思路] 状压D

bzoj 1879: [Sdoi2009]Bill的挑战【状压dp】

石乐志写容斥--其实状压dp就行 设f[i][s]表示前i个字母,匹配状态为s,预处理g[i][j]为第i个字母是j的1~n的集合,转移的时候枚举26个字母转移,最后答案加上正好有k个的方案即可 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1000003; int T,n,m,len,t,f[55][50005],g[55][27],an

bzoj1879: [Sdoi2009]Bill的挑战 状压dp

题目传送门 https://www.lydsy.com/JudgeOnline/problem.php?id=1879 题解 我们考虑用\(p[i][j]\)存所有字符串的信息,\(i\)表示字符串的第\(i\)个字符,\(j\)表示英文字母\(a-z\),\(p[i][j]\)用二进制存,例如\(p[1][0]=1100\)表示第一位可以为\(a\)的为第一个字符串和第二个字符串. 然后我们按字符串长度\(dp\),\(f[i][j]\)表示方案数,\(i\)表示字符串的第\(i\)个字符,\

[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)

[BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关系,那么空间为26^50,爆内存: 方案2:把每一个串压起来,多开一维记录匹配字符,那么空间为nlen26,合法,但不便于状态的设计和转移: 方案3:把每一个串同一个位置的字符放在一起,用一个布尔数组记录与每一个小写字母的匹配关系,那么空间为26^15*len,爆内存: 方案4:把每一个串同一个位置

SDOI 2009 BIll的挑战

题目描述 Description Sheng bill不仅有惊人的心算能力,还可以轻松地完成各种统计.在昨天的比赛中,你凭借优秀的程序与他打成了平局,这导致Sheng bill极度的不满.于是他再次挑战你.这次你可不能输! 这次,比赛规则是这样的: 给N个长度相同的字符串(由小写英文字母和′?′组成),S1,S2,...,SN,求与这N个串中的刚好K个串匹配的字符串T的个数(答案模1000003). 若字符串Sx(1 ≤ x ≤ N)和T匹配,满足以下条件: 1. Sx.length = T.l

BZOJ1879 Bill的挑战

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1879 本来是一道水题(~~~~(>_<)~~~~). 开始SB了,敲了个AC自动机dp,MLE 发现数据中 '?' 好多呀 ~~~~(>_<)~~~~ 空间变$O(len^2)$ 然后去想朴素dp,枚举一下那些集合和T匹配,然后$O(n \cdot 2^n)$ dp,又W又T一是爽. TLE 40: #include <cstdio> #include <cs