zoukankan      html  css  js  c++  java
  • NTT

    链接:https://www.nowcoder.com/acm/contest/133/D
    来源:牛客网

    题目描述

    Applese打开了m个QQ群,向群友们发出了组队的邀请。作为网红选手,Applese得到了n位选手的反馈,每位选手只会在一个群给Applese反馈
    现在,Applese要挑选其中的k名选手组队比赛,为了维持和各个群的良好关系,每个群中都应有至少一名选手成为Applese的队友(数据保证每个群都有选手给Applese反馈)
    Applese想知道,他有多少种挑选队友的方案

    输入描述:

    输入包括两行
    第一行包括三个数n, m, k,表示共有n位选手,m个群,需要有k名选手被选择
    第二行包括m个数,第i个数表示第i个群有si个选手
    n ≤ 100000, m ≤ k ≤ n

    输出描述:

    输出包括一行
    第一行输出方案数
    由于输出可能比较大,你只需要输出在模998244353意义下的答案
    示例1

    输入

    5 3 4
    1 2 2

    输出

    4

    思路分析: dp[i][j] 表示前 i 个QQ 群中选了 j 个人的方案数,并且保证每个群中至少选 1 人
        dp[i][j] += dp[i-1][j-h]*C(x, h) , 其实本质意思就是第一个群选 1个, 2个,... n 个所对应的方案 * 第二个群选 1个, 2个, ... n个,这不就是个多项式的乘法吗,又因为其带模数,所以一个NTT,就可以了
    代码示例 :

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long 
    const ll maxn = 1e5+5;
    const ll mod = 998244353;
    ll n, m, k;
    vector<ll>ve[maxn];
    ll pp[maxn], inv[maxn];
    
    ll qw(ll a, ll b){
    	ll res = 1;
    	a %= mod;
    	while(b){
    		if (b&1) res = res*a%mod;
    		a = a*a%mod;
    		b >>= 1;
    	}
    	return res;
    }
    
    ll C(ll n, ll m){
    	ll ans = pp[n]*inv[m]%mod*inv[n-m]%mod;
    	return ans;
    }
    
    ll rev (ll x, ll len){
    	ll ret = 0;
    	for(ll i = 0; (1<<i)<len; i++){
    		ret <<= 1;
    		if ((1<<i)&x) ret |= 1;
    	}
    	return ret;
    }
    
    void NTT(vector<ll>& p, ll len, ll DFT){
    	for(ll i = 0; i < len; i++){
    		ll x= rev(i, len);
    		if (i < x) swap(p[i], p[x]);
    	}
    	for(ll i = 1; i < len; i <<= 1){
    		ll wn = qw(3, (mod-1)/(2*i));
    		if (DFT == -1) wn = qw(wn, mod-2);
    		for(ll j = 0; j < len; j += i*2){
    			ll w = 1;
    			for(ll k = 0; k < i; k++){
    				ll x = p[j+k];
    				ll y = w*p[j+k+i]%mod;
    				p[j+k]=(x+y)%mod;
    				p[j+k+i]=(x-y+mod)%mod;
    				w = w*wn%mod;
    			}
    		}
    	}
    	if (DFT == -1) 
    		for(ll i = 0, x = qw(len, mod-2); i < len; i++)
    			p[i]=p[i]*x%mod;
    }
    
    void mul(vector<ll>& a, vector<ll> b){
    	ll n = a.size(), m = b.size();
    	ll len = 1;
    	while(len < (n+m)) len <<= 1;
    	a.resize(len);
    	b.resize(len);
    	NTT(a, len, 1);
    	NTT(b, len, 1);
    	for(ll i = 0; i < len; i++) a[i] = a[i]*b[i]%mod;
    	NTT(a, len, -1);
    	a.resize(n+m);
    }
    
    queue<ll>que;
    int main() {
    	ll x;
    	pp[0] = 1;
    	for(ll i = 1; i <= 100000; i++) pp[i]=pp[i-1]*i%mod;
    	for(ll i = 0; i <= 100000; i++) inv[i]=qw(pp[i],mod-2);
    	
    	cin >> n >> m >> k;
    	for(ll i = 1; i <= m; i++){
    		scanf("%lld", &x);		
    		ve[i].resize(x);
    		for(ll j = 0; j < x; j++) ve[i][j] = C(x, j+1); // 下标从0开始 
    		que.push(i);
    	}
    	while(que.size() > 1){
    		ll u = que.front(); que.pop();
    		ll v = que.front(); que.pop();
    		mul(ve[u], ve[v]);
    		que.push(u);
    	}
    	printf("%lld
    ", ve[que.front()][k-m]);
    	//for(ll i = 0; i <= ve[que.front()].size(); i++) printf("++%lld %lld 
    ",i, ve[que.front()][i]);
    	return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    SQL 去重 DISTINCT 语法
    urllib2 urllib urllib3的区别联系
    urllib库中常见的类和方法
    python模块之json pickle
    python os模块
    python的常见内置模块之-----time
    列表,队列,栈,链表的内存模型
    open函数
    session和cookie
    随笔小skill
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/9512139.html
Copyright © 2011-2022 走看看