列表

详情


NC19984. [HAOI2011]PROBLEM C

描述

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

输入描述

第一行一个整数T,表示数据组数
对于每组数据,第一行有三个整数,分别表示n、m、M
若m不为0,则接下来一行有m对整数,p1、q1,p2、q2 ,…, pm、qm,其中第i对整数pi、qi表示第pi个人的编号必须为qi  

输出描述

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

示例1

输入:

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

输出:

YES 4
NO

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 930ms, 内存消耗: 1912K, 提交时间: 2020-02-15 20:56:20

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 310
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
ll n, m, mod, res[maxn], C[maxn][maxn], f[maxn][maxn], s[maxn][maxn];
int main()
{
    ll i, j, k, T=read(), ans;
    while(T--)
    {
        n=read(), m=read(), mod=read();
        rep(i,1,n)res[i]=n-i+1;
        rep(i,1,m)
        {
            ll p=read(), q=read();
            rep(j,1,q)res[j]--;
        }
        rep(i,0,n)C[i][0]=1;
        rep(i,1,n)rep(j,1,i)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        rep(i,1,n)if(res[i]<0){printf("NO\n");break;}if(i<=n)continue;
        printf("YES ");
        if(n==m){printf("1\n");continue;}
        ans=1;
        cl(f);
        f[1][res[1]]=1;
        rep(i,2,n)rep(j,1,res[i])
        {
            rep(k,j,n)f[i][j]+=f[i-1][k]*C[k][j]%mod;
            f[i][j]%=mod;
            (ans+=f[i][j])%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 518ms, 内存消耗: 2664K, 提交时间: 2020-04-02 12:48:20

#include<cstdio>
#include<cstring>
const int MAXN=399;
int n,m,M,cnt[MAXN],sum[MAXN],i;
long long c[MAXN][MAXN],f[MAXN][MAXN];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(cnt,0,sizeof(cnt));
		memset(sum,0,sizeof(sum));
		memset(f,0,sizeof f);
		scanf("%d%d%d",&n,&m,&M);
		for(i=0;i<=n;i++)
		c[i][0]=c[i][i]=(1%M);
		for(i=1;i<=n;i++)
		for(int j=1;j<=i;j++)
		c[i][j]=(c[i-1][j]+c[i-1][j-1])%M;
		for(i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			cnt[y]++;
		 } 
		 sum[0]=n-m;
		 for(i=1;i<=n;i++)
		 {
		 	sum[i]=sum[i-1]+cnt[i];
		 	if(sum[i]<i)
		 	{
		 		puts("NO");
		 		break;
			 }
		 }
		 if(i!=(n+1))
		 continue;
		 f[0][0]=1;
		 for(i=1;i<=n;i++)
		 for(int j=sum[i];j>=i;j--)
		 for(int k=j-i+1;k>=cnt[i];k--)
		 f[i][j]=(f[i][j]+f[i-1][j-k]*c[sum[i]-(j-k)-cnt[i]][k-cnt[i]])%M;
		 printf("YES %lld\n",f[n][n]);
	}
	return 0;
}

上一题