zoukankan      html  css  js  c++  java
  • UOJ#209. 【UER #6】票数统计 组合+容斥

    自己独立想出来的,开心.         

    首先,对于 $x$ 不等于 $y$ 的情况,显然只限制前缀/后缀.    

    然后如果没有 x 与 y 相等的情况的话我们完全可以枚举总的 1 的个数,然后限制后缀的就可以转化成限制前缀的.   

    如果引入 x 与 y 相等的情况,也就是说要求前缀或后缀都填满也按照上述方式处理即可.  

    但是要简单容斥一下,即 ans(前缀)+ans(后缀)-ans(前后缀)    

    code:  

    #include <bits/stdc++.h>    
    #define N 5009   
    #define ll long long
    #define mod 998244353 
    #define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout)  
    using namespace std;     
    int C[N][N],n,m,lim,tot; 
    struct node { int x,y; } ch[N];  
    struct data 
    { 
        int x,y; 
        bool operator<(const data b) const { return x<b.x; }   
    }tmp[N],A[N];         
    void init() 
    {
        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]=(ll)(C[i-1][j]+C[i-1][j-1])%mod;   
        }                                 
    }         
    int sol() 
    {        
        sort(tmp+1,tmp+1+tot);     
        if(tmp[1].x==0&&tmp[1].y) return 0;     
        int ans=1,dist,det; 
        tmp[0].x=0,tmp[0].y=0;       
        for(int i=1;i<=tot;++i) 
        {    
            det=tmp[i].y-tmp[i-1].y;  
            dist=tmp[i].x-tmp[i-1].x;       
            if(dist<det||tmp[i].y<0||det<0) return 0;        
            ans=(ll)ans*C[dist][det]%mod;   
        }           
        return ans;   
    }
    int calc(int TOT)       
    {
        // 总共有 TOT 个 1    
        tot=0;              
        for(int i=1;i<=m;++i) 
        {
            if(ch[i].x!=ch[i].y)  
            {   
                ++tot; 
                if(ch[i].x>ch[i].y) {        
                    A[tot].x=ch[i].x;  
                    A[tot].y=ch[i].y;    
                }
                else {   
                    A[tot].x=n-ch[i].y;  
                    A[tot].y=TOT-ch[i].x;              
                }     
            }
        }         
        ++tot;  
        A[tot].x=n;  
        A[tot].y=TOT;              
        int ans=0;             
        if(!lim) {       
            for(int i=1;i<=tot;++i) tmp[i]=A[i];   
            return sol();  
        }   
        else {       
            ++tot;   
            //============================ 只有前 
            A[tot].x=lim;  
            A[tot].y=lim;   
            for(int i=1;i<=tot;++i) tmp[i]=A[i];        
            (ans+=sol())%=mod;        
            //============================ 只有后   
            A[tot].x=n-lim;          
            A[tot].y=TOT-lim;      
            for(int i=1;i<=tot;++i) tmp[i]=A[i];  
            (ans+=sol())%=mod;     
            //============================ 前后都有      
            ++tot;  
            A[tot].x=lim;  
            A[tot].y=lim;  
            for(int i=1;i<=tot;++i) tmp[i]=A[i];   
            (ans+=mod-sol())%=mod;                 
            return ans; 
        }
    }
    void solve() 
    {
        scanf("%d%d",&n,&m);      
        for(int i=1;i<=m;++i) {
            scanf("%d%d",&ch[i].x,&ch[i].y);   
            if(ch[i].x==ch[i].y) lim=max(lim,ch[i].x);        
        }                            
        // 序列中有 i 个 1                         
        int ans=0;    
        for(int i=0;i<=n;++i) 
        {        
            ans+=calc(i);              
            if(ans>=mod) ans-=mod;
        }    
        printf("%d
    ",ans);   
        lim=tot=0;   
    }
    int main() 
    {
        // setIO("input");     
        int T;  
        init();  
        scanf("%d",&T);   
        while(T--) solve();                     
        return 0; 
    }
    

      

  • 相关阅读:
    Spyder | 关于报错No module named 'PyQt5.QtWebKitWidgets'
    Java基础(11) | 接口
    Java基础(10) | 抽象
    Java基础(9) | 继承
    Java基础(7) | String
    Java基础(6) | ArrayList
    CodeBlocks17.12配置GNU GCC + 汉化
    图片懒加载
    Mac安装Mysql 超详细(转载)
    剑指 Offer 03. 数组中重复的数字
  • 原文地址:https://www.cnblogs.com/guangheli/p/13143838.html
Copyright © 2011-2022 走看看