[杂题 计数] UOJ#209【UER #6】寻找罪犯

来源:互联网 发布:用python搭建知识图谱 编辑:程序博客网 时间:2024/06/06 01:30

注意到,若 x<y ,只可能是限制 sufsumy=x,若 x>y, 只可能是限制 presumx=y,只有x=y 的时候有两种可能:sufsumx=xpresumx=x
注意到最后一种限制很特殊,只需要满足最大的,其他的都满足了。
所以需要讨论的限制只有一个,这样就简单了。
问题转化为,给一些前缀和,后缀和的值的限制,求方案数。
注意到可以O(n2),就枚举 presumn 的值,把所有后缀的限制都转化位前缀的,这样就可以相邻限制之间组合数算了。

代码能力还要加强。。。

#include<cstdio>#include<algorithm>#include<cstring>#define mp(x,y) make_pair(x,y)#define Fir first#define Sec secondusing namespace std;typedef long long LL;const int maxn=5005, MOD=998244353;int n,m,_test,_max,len1,len2,len3;pair<int,int> a1[maxn],a2[maxn];struct data{    int x,y,k; //k=0: sumL[x]=y;   k=1: sumL[x]=sum_n-y;    data(int t1=0,int t2=0,int t3=0){x=t1;y=t2;k=t3;}    bool operator < (const data &B)const{        return x<B.x;    }} b[maxn];LL fac[maxn],inv[maxn],fac_inv[maxn],ans,res; LL C(int n,int m){ return (n<m||n<0||m<0)?0:(fac[n]*fac_inv[m]%MOD*fac_inv[n-m]%MOD); }LL Get(int sum_n){    LL res=1;    for(int i=1,lst_p=0,lst_s=0;i<=len3;i++){        int now_p=b[i].x, now_s=b[i].k?sum_n-b[i].y:b[i].y;        (res*=C(now_p-lst_p,now_s-lst_s))%=MOD; if(res==0) return 0;        lst_p=now_p; lst_s=now_s;    }    return res;}LL Calc(){    len3=0;    for(int i=1;i<=len1;i++) b[++len3]=data(a1[i].Fir,a1[i].Sec,0);    for(int i=1;i<=len2;i++) b[++len3]=data(n-a2[i].Fir,a2[i].Sec,1);    sort(b+1,b+1+len3); b[++len3]=data(n,0,0);    LL res=0;    for(int i=0;i<=n;i++)     b[len3].y=i, (res+=Get(i))%=MOD;    return res;}int main(){    freopen("A.in","r",stdin);    freopen("A.out","w",stdout);    fac[0]=1; for(int i=1;i<=5000;i++) fac[i]=fac[i-1]*i%MOD;    inv[1]=1; for(int i=2;i<=5000;i++) inv[i]=(LL)(MOD-MOD/i)*inv[MOD%i]%MOD;    fac_inv[0]=1; for(int i=1;i<=5000;i++) fac_inv[i]=fac_inv[i-1]*inv[i]%MOD;    scanf("%d",&_test);    while(_test--){        ans=0; _max=len1=len2=0;        scanf("%d%d",&n,&m);        for(int i=1;i<=m;i++){            int x,y; scanf("%d%d",&x,&y);            if(x==y) _max=max(_max,x); else            if(x>y) a1[++len1]=mp(x,y);               else a2[++len2]=mp(y,x);         }        a1[++len1]=a2[++len2]=mp(_max,_max);        ans=-Calc();        len1--; (ans+=Calc())%=MOD;         len1++; len2--; (ans+=Calc())%=MOD;        printf("%lld\n",(ans+MOD)%MOD);    }    return 0;}
原创粉丝点击