BZOJ 2302: [HAOI2011]Problem c [DP 组合计数]

2302: [HAOI2011]Problem c

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 648  Solved: 355
[Submit][Status][Discuss]

Description

给n个人安排座位,先给每个人一个1~n的编号,设第i个人的编号为ai(不同人的编号可以相同),接着从第一个人开始,大家依次入座,第i个人来了以后尝试坐到ai,如果ai被占据了,就尝试ai+1,ai+1也被占据了的话就尝试ai+2,……,如果一直尝试到第n个都不行,该安排方案就不合法。然而有m个人的编号已经确定(他们或许贿赂了你的上司...),你只能安排剩下的人的编号,求有多少种合法的安排方案。由于答案可能很大,只需输出其除以M后的余数即可。

Input

第一行一个整数T,表示数据组数

对于每组数据,第一行有三个整数,分别表示n、m、M

若m不为0,则接下来一行有m对整数,p1、q1,p2、q2 ,…, pm、qm,其中第i对整数pi、qi表示第pi个人的编号必须为qi

Output

对于每组数据输出一行,若是有解则输出YES,后跟一个整数表示方案数mod M,注意,YES和数之间只有一个空格,否则输出NO

Sample Input

2
4 3 10
1 2 2 1 3 1
10 3 8882
7 9 2 9 5 10

Sample Output

YES 4
NO

HINT

100%的数据满足:1≤T≤10,1≤n≤300,0≤m≤n,2≤M≤109,1≤pi、qi≤n   且保证pi互不相同。



想了一种做法,根据每个人最后做的位置,因为右面对左面有影响倒着DP,但是不对

orz http://blog.csdn.net/fzhvampire/article/details/44954631

可以发现,我们并不关心每个人最后坐在那里,我们只关心给他的编号,也就是一开始把他放在那里让他往后找

仍然倒着DP,f[i][j]表示座位i..n放了j个人,然后枚举位置i放了几个人,乘上个组合数转移就行了

无解的情况就是一个位置i右面的座位数少于编号>=i的人数,用s[i]表示给定的编号>=i的人数

这样的话正着DP也可以,因为不依赖于最后坐的位置了

注意:j和k的枚举范围

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=305;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}
int n,m,MOD,x,y,s[N];
ll f[N][N],c[N][N];
void dp(){
    c[0][0]=1;
    for(int i=1;i<=n;i++){
        c[i][0]=1;
        for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
    }

    f[n+1][0]=1;
    for(int i=n;i>=1;i--)
        for(int j=0;j<=n-i+1-s[i];j++)
            for(int k=0;k<=j;k++) f[i][j]=(f[i][j]+f[i+1][j-k]*c[j][k])%MOD;
    printf("YES %lld\n",f[1][n-s[1]]);
}
int main(){
    //freopen("in.txt","r",stdin);
    int T=read();
    while(T--){
        int flag=1;
        memset(s,0,sizeof(s));
        memset(f,0,sizeof(f));
        n=read();m=read();MOD=read();
        for(int i=1;i<=m;i++) x=read(),y=read(),s[y]++;
        for(int i=n;i>=1;i--){
            s[i]+=s[i+1];
            if(s[i]>n-i+1) puts("NO"),flag=0;
        }
        if(flag) dp();
    }
}
时间: 2024-12-09 22:14:01

BZOJ 2302: [HAOI2011]Problem c [DP 组合计数]的相关文章

BZOJ 2302: [HAOI2011]Problem c( dp )

dp(i, j)表示从i~N中为j个人选定的方案数, 状态转移就考虑选多少人为i编号, 然后从i+1的方案数算过来就可以了. 时间复杂度O(TN^2) --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long lo

BZOJ 2302 HAOI2011 Problem c 动态规划

题目大意:给定n个人和n个位置,要求生成一个序列ai,然后第1...n个人依次走到第a1...n个位置,如果那个位置已经有人了就走到下一个位置,直到找到一个空位,坐下.如果找完第n个座位还是没有找到就称这个序列不合法 现在已经确定了一些ai,求合法序列的数量 一个序列合法等价于编号≤i的人至少有i个 然后就可以DP辣... 令fi,j表示编号≤i的人有j个的方案数,cnti表示确定编号为i的人的个数,sumi表示编号可以≤i的人的个数 那么有 fi,j=∑j?i+1k=cntifi?1,j?k?

BZOJ 2301: [HAOI2011]Problem b(莫比乌斯反演 + 容斥原理 + 分块优化)

传送门 Problem 2301. – [HAOI2011]Problem b 2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 3671  Solved: 1643[Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input

BZOJ 2298: [HAOI2011]problem a 动态规划

2298: [HAOI2011]problem a Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2298 Description 一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai.bi Outp

3.29省选模拟赛 除法与取模 dp+组合计数

LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采用二进制状压是不明智的 2的个数最多为13个 2^13也同样到达了1e4的复杂度. 考虑 hash状压 即 2的个数有x个 那么我们就有状态w表示2还有x个. 这样做的原因是把一些相同的东西给合并起来 而并非分散开来.即有多个2直接记录有多少个即可. 可以发现 这样做不同的除数最多只有5个 状态量较

[BZOJ 2301] [HAOI2011] Problem b

2301: [HAOI2011]Problem b Time Limit: 50 SecMemory Limit: 256 MB Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数 Sample Input 2 2 5 1 5

BZOJ 2301([HAOI2011]Problem b-mobius反演)

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2170  Solved: 934 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Out

BZOJ 2301 [HAOI2011]Problem b (容斥+莫比乌斯反演+分块优化 详解)

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2096  Solved: 909 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Out

【BZOJ2298】[HAOI2011]problem a DP

[BZOJ2298][HAOI2011]problem a Description 一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai.bi Output 一个整数,表示最少有几个人说谎 Sample Input 3 2 0 0 2 2 2 Sample Output 1 HINT 100%的数据满足: 1≤n≤100000   0≤