多校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
原文地址:https://www.cnblogs.com/Cw-trip/p/4731559.html