【NOI2017模拟6.22】排列问题
来源:互联网 发布:程序员 工资 编辑:程序博客网 时间:2024/05/21 22:57
题目大意
有n种球,每种球有不同的颜色,第i种球有a[i]个,现在将这些球排成一排,给出q组询问,每组询问给出一个数x,询问满足相邻的球颜色相同的个数为x的排列个数。
设m为所有球的个数和,数据满足:
题解
设g[i]表示所有球总共被分成i段的方案数(注意,g[i]所描述的每一段的颜色一定是一样的,但是相邻的段的颜色是可能一样的)
如果第i种球被分成了b[i]段,那么方案数就是:
大力分治一波+ntt就好了
设f是答案
那么,将g调换有:
这个式子的意义是:如果被分成了m-i段,那么相邻的球颜色相同的个数至少为i,考虑一个相邻球颜色相同个数位j的排列在其中会被计算
接着有
将
得到:
上面就是一个卷积形式了
设:
那么有:
所以就要做多项式求逆,然后直接乘就好了,注意转化过程中的颠倒的问题
代码
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<set>#include<bitset>#include<map>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;int get(){ char ch; while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-'); if (ch=='-'){ int s=0; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return -s; } int s=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return s;}const int MAXN = 600010;const int MAXL = 20;const int mo = 998244353;const int G = 3;int n,a[MAXN];int st[MAXN],k;int m;int v[MAXN];int A[MAXN],B[MAXN];LL ny[MAXN],js[MAXN],e[MAXN];int g[MAXN],f[MAXN],h[MAXN],H[MAXN];LL d[MAXN];int bitr[MAXN];int N,L;int mi[23];LL quickmi(LL x,LL tim){ LL ans=1; for(;tim;tim/=2,x=x*x%mo) if (tim%2)ans=ans*x%mo; return ans;}void prepare(){ int v=quickmi(G,(mo-1)/N); d[0]=1; fo(i,1,N)d[i]=d[i-1]*v%mo; fo(i,0,N-1){ bitr[i]=0; fo(j,0,L-1) if ((i&mi[j])>0)bitr[i]+=mi[L-1-j]; }}int add(int x,int y){ return x+y>=mo?x+y-mo:x+y;}void DFT(int *a){ fo(i,0,N-1) if (i<bitr[i])swap(a[i],a[bitr[i]]); for(int now=2;now<=N;now<<=1){ int half=now/2; fo(i,0,half-1){ int w=d[N/now*i]; for(int j=i;j<N;j+=now){ int l=a[j],r=1ll*w*a[j+half]%mo; a[j]=add(l,r); a[j+half]=add(l,(mo-r)%mo); } } }}void IDFT(int *a){ fo(i,0,N-1) if (i<bitr[i])swap(a[i],a[bitr[i]]); for(int now=2;now<=N;now<<=1){ int half=now/2; fo(i,0,half-1){ int w=d[N-N/now*i]; for(int j=i;j<N;j+=now){ int l=a[j],r=1ll*w*a[j+half]%mo; a[j]=add(l,r); a[j+half]=add(l,(mo-r)%mo); } } } LL tmp=quickmi(N,mo-2); fo(i,0,N-1)a[i]=tmp*a[i]%mo;}void get_nv(int *f,int *f0,int len){ if (len==1){ f0[0]=quickmi(f[0],mo-2); return; } get_nv(f,f0,(len+1)/2); N=1;L=0; while(N<=2*len){N<<=1;L++;} prepare(); fo(i,0,N-1)A[i]=B[i]=0; fo(i,0,(len+1)/2-1)B[i]=f0[i]; fo(i,0,len-1)A[i]=f[i]; DFT(A); DFT(B); fo(i,0,N-1)A[i]=1ll*B[i]*(2ll+mo-1ll*A[i]*B[i]%mo)%mo; IDFT(A); fo(i,0,len-1)f0[i]=A[i];}int main(){ freopen("color.in","r",stdin); freopen("color.out","w",stdout); mi[0]=1; fo(i,1,20)mi[i]=mi[i-1]<<1; n=get(); js[0]=ny[0]=1; fo(i,1,200000)js[i]=js[i-1]*i%mo; ny[200000]=quickmi(js[200000],mo-2); fd(i,199999,1)ny[i]=ny[i+1]*(i+1)%mo; fo(i,1,200000)e[i]=ny[i]*js[i-1]%mo; fo(i,1,n){ st[++k]=m+1; m+=(a[i]=get())+1; LL now=1; fo(j,0,a[i]-1){ v[st[k]+j+1]=now*ny[j+1]%mo; now=now*e[j+1]%mo*(a[i]-1-j)%mo; } } for(N=1,L=0;k>1;N<<=1,L++){ prepare(); int k_=k; k=0; for(int now=1,w=1;now<=k_;now=w+1){ if ((now<k_&&a[now]+a[now+1]>=N)||(now==k_)){ st[++k]=st[now]; a[k]=a[now]; w=now; continue; } w=now+1; fo(i,0,a[now])A[i]=v[st[now]+i]; fo(i,0,a[w])B[i]=v[st[w]+i]; DFT(A); DFT(B); fo(i,0,N-1)A[i]=1ll*A[i]*B[i]%mo; IDFT(A); fo(i,0,a[now]+a[w])v[st[now]+i]=A[i]; fo(i,0,N-1)A[i]=B[i]=0; st[++k]=st[now]; a[k]=a[now]+a[w]; } } m-=n; fo(i,0,m)g[i]=1ll*v[i+1]*js[m-i]%mo*js[i]%mo; fo(i,0,m)h[i]=ny[i]; get_nv(h,H,m+1); if (N<=2*m){ N<<=1;L++; prepare(); } DFT(g); DFT(H); fo(i,0,N-1)f[i]=1ll*g[i]*H[i]%mo; IDFT(f); fo(i,0,m)f[i]=1ll*f[i]*ny[m-i]%mo; fo(i,0,m/2)swap(f[i],f[m-i]); for(int q=get();q;q--){ int x=get(); if (x>m)printf("0\n"); else printf("%d\n",f[x]); } fclose(stdin); fclose(stdout); return 0;}
阅读全文
0 0
- 【NOI2017模拟6.22】排列问题
- 【NOI2017模拟6.22】没有上司的舞会
- NOI2017模拟3.1 总结
- NOI2017模拟3.8 总结
- 【NOI2017模拟3.30】原谅
- 【NOI2017模拟4.2】查询
- 【NOI2017模拟4.2】押韵
- 【NOI2017模拟6.26】A
- 【NOI2017模拟6.29】呵呵
- 【NOI2017模拟6.2】字符串
- 【JZOJ5037】【NOI2017模拟3.30】轮回
- [JZOJ100003]【NOI2017模拟.4.1】 Tree
- 【JZOJ5036】【NOI2017模拟3.30】原谅
- 【JZOJ5037】【NOI2017模拟3.30】轮回
- 【JZOJ5040】【NOI2017模拟4.2】押韵
- 【JZOJ5039】【NOI2017模拟4.2】查询
- 【JZOJ100003】【NOI2017模拟.4.1】 Tree
- 【JZOJ100004】【NOI2017模拟.4.1】 Dice
- 为什么ConstraintLayout代替其他布局?
- 剑指offer面试题[9]-裴波那契数列
- Postman用法简介-Http请求模拟工具
- 谁说 JavaScript 简单的
- 1009. Product of Polynomials (25)
- 【NOI2017模拟6.22】排列问题
- 在 HTML 中使用 JavaScript
- 使用jspSmartUpload组件进行文件上传、下载、批量下载
- java中各种集合解析以及区别
- 【机器学习算法模型】分类算法——logistic回归
- 关于cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题(不需要修改任何代码,只需要一个配置)
- php数据库扩展
- java程序员面试真题及详解2017(纯手动)
- Visual stuidio 快捷键的修改、查询