zoukankan      html  css  js  c++  java
  • 多校8-1010 HDU5389 (dp

    题目:每个人有1~9的编号,有两个门,一帮人能进门,当且仅当这些人的编号之和与门的编号同余。问把这些人安排到两个门有多少种方法。

    思路:比赛的时候有点脑抽,想了好久才发现是个简单dp。。。。只需要统计每个编号的人数,然后dp[i][j]表示前i个编号的人组成j同余的方案数,然后由于每种人选9的倍数个是无影响的,所以每种选择实际上是选x个,x+9,x+18……个,那么转移状态的时候需要计算n个数里选x个,x+9,x+18……个的方案数之和,这个怎么计算呢?利用一个递推式C[n][k]=C[n][k-1]*(n-k)/(k+1)(除法要用逆元代替),可以在O(n)的复杂度内一次得到所有这些值,计算的时候加到相应的组里就好了。

    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio(false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps 0.00000001
    #define IINF (1<<30)
    typedef long long ll;
    typedef long long LL;
    typedef long long lint;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    const int mod=258280327;
    const int maxv=1e5+300;
    inline ll qpow(ll x,ll p){
        ll ans=1;
        while(p>0){
            if(p&1){
                ans=(ans*x)%mod;
            }
            x=(x*x)%mod;
            p>>=1;
        }
        return ans;
    }
    ll inv[maxv];
    void init(){
        inv[1]=1;
        for(int i=2;i<maxv;i++){
            inv[i]=qpow(i,mod-2);
        }
    }
    ll dp[15][15];
    int cnt[15];
    int T;
    int n,a,b;
    ll tol=0;
    ll CC[10];
    int main(){
        ////////freopen("/home/files/CppFiles/TeamContest/in","r",stdin);
        init();
        cin>>T;
        while(T--){
            memset(dp,0,sizeof dp);
            memset(cnt,0,sizeof cnt);
            tol=0;
            scanf("%d%d%d",&n,&a,&b);
            for(int i=0;i<n;i++){
                int x;
                scanf("%d",&x);
                cnt[x]++;
                tol+=x;
            }
            if((a+b)%9!=tol%9){
                if(tol%9==a%9||tol%9==b%9){
                    if(a==b){
                        cout<<2<<endl;
                        continue;
                    }
                    cout<<1<<endl;
                    continue;
                }else{
                    cout<<0<<endl;
                    continue;
                }
            }
            dp[0][0]=1;
            for(int i=1;i<=9;i++){
                memset(CC,0,sizeof CC);
                ll Cn=1;
                for(int k=0;k<=cnt[i];k++){
                    CC[k%9]=(CC[k%9]+Cn)%mod;
                    Cn=(Cn*(cnt[i]-k)%mod*inv[k+1])%mod;
                }
                for(int j=0;j<=min(cnt[i],8);j++){
                    for(int k=0;k<9;k++){
                        dp[i][(k+i*j)%9]=(dp[i][(k+i*j)%9]+dp[i-1][k]*(CC[j])%mod)%mod;
                    }
                }
            }
            if(a==9) a=0;
            cout<<dp[9][a]<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    git add用法
    git删除指定文件夹
    git相关命令
    Stacktrace: org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:5
    [程序员代码面试指南]数组和矩阵-子矩阵的最大累加和问题
    [程序员代码面试指南]二叉树问题-统计完全二叉树的节点数
    [排序]直接插入排序、希尔排序
    [程序员代码面试指南]判断字符数组中是否所有字符只出现一次(堆排序)
    [SpringBoot项目]笔记
    [计算机网络]知识点
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4731559.html
Copyright © 2011-2022 走看看