解题:CF960G Bandit Blues & FJOI 2016 建筑师
两个题推导是一样的,具体实现不一样,所以写一起了,以FJOI 2016 建筑师 的题面为标准
前后在组合意义下一样,现在只考虑前面,可以发现看到的这a个建筑将这一段划分成了a-1个区间,区间里的数随意填。
看起来可以用组合数算,但是还要考虑看到的建筑,所以我们把每个建筑和它后面这段区间合起来看。设区间的长度是len,这就是一个len+1个数的圆排列(等于len!,相当于固定一个开头后面随便排)
这样考虑前后就是将n-1个数划分为a+b-2个全排列,n-1是因为最高的那个在两边都没被算进去,是第一类斯特林数。同时a+b-2个圆排列之间还要选出来a-1个放前面,乘上组合数即可。现在关键是如何求第一类斯特林数。
FJOI那道题n*k不是很大,可以直接$O(nk)$递推,边界条件是$S[0][0]=1$,转移是$S[i][j]=S[i-1][j-1]+S[i-1][j]*(i-1)$
CF那道题只有一次询问,但是n,k都很大,我们考虑第一类斯特林数在第一维固定下的生成函数:$G(x)=\prod\limits_{i=0}^{n-1}(x+i)$,x是从$s[i-1][j-1]$来的,i-1是从$s[i-1][j]*(i-1)$来的。用分治NTT优化
Code1
//Simple NTT
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define vint vector<int>
using namespace std;
const int N=,mod=;
int fac[N],inv[N],rev[N];
int aa[N],bb[N],pw[][];
int a,b,n,l1,l2,G,Gi,Ni; vint stl;
int Qpow(int x,int k)
{
if(k==) return x;
int tmp=Qpow(x,k/);
return k%?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod;
}
int C(int a,int b)
{
return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
}
void SPJ()
{
if(!a||!b||n-<a+b-) printf(""),exit();
if(n==) printf(""),exit();
}
void Pre()
{
fac[]=inv[]=,G=,Gi=Qpow(G,mod-);
for(int i=;i<=;i++)
{
pw[i][]=Qpow(G,(mod-)/(<<i));
pw[i][]=Qpow(Gi,(mod-)/(<<i));
}
for(int i=;i<=a+b;i++) fac[i]=1ll*fac[i-]*i%mod;
inv[a+b]=Qpow(fac[a+b],mod-);
for(int i=a+b-;i;i--) inv[i]=1ll*inv[i+]*(i+)%mod;
}
void Prework(vint &a,vint &b)
{
register int i;
l1=a.size()-,l2=b.size()-;
l1+=l2,l2=; while(l2<=l1) l2<<=;
a.resize(l2),b.resize(l2);
for(i=;i<=l2;i++) aa[i]=a[i];
for(i=;i<=l2;i++) bb[i]=b[i];
for(i=;i<l2;i++)
rev[i]=(rev[i>>]>>)+(i&)*(l2>>);
}
void Trans(int *arr,int len,int typ)
{
register int i,j,k;
for(i=;i<len;i++)
if(rev[i]>i) swap(arr[rev[i]],arr[i]);
for(i=;i<=len;i<<=)
{
int lth=i>>,ort=pw[(int)log2(i)][typ==-];
for(j=;j<len;j+=i)
{
int ori=,tmp;
for(k=j;k<j+lth;k++,ori=1ll*ori*ort%mod)
{
tmp=1ll*ori*arr[k+lth]%mod;
arr[k+lth]=(arr[k]-tmp+mod)%mod;
arr[k]=(arr[k]+tmp)%mod;
}
}
}
if(typ==-)
{
int Ni=Qpow(len,mod-);
for(i=;i<=len;i++)
arr[i]=1ll*arr[i]*Ni%mod;
}
}
vint NTT(vint a,vint b)
{
Prework(a,b);
Trans(aa,l2,),Trans(bb,l2,);
for(int i=;i<l2;i++) aa[i]=1ll*aa[i]*bb[i]%mod;
Trans(aa,l2,-);
vint ret; ret.clear();
for(int i=;i<l2;i++) ret.push_back(aa[i]);
return ret;
}
vint CDQ(int l,int r)
{
if(l==r) return {l,};
else
{
int mid=(l+r)/;
vint a1=CDQ(l,mid),a2=CDQ(mid+,r);
return NTT(a1,a2);
}
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
SPJ(),Pre(),stl=CDQ(,n-);
printf("%d",1ll*C(a+b-,a-)*stl[a+b-]%mod);
return ;
}
Code2
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=,mod=1e9+;
int fac[N],inv[N],S[N][M];
int a,b,n,T,l1,l2,G,Gi,Ni;
int Qpow(int x,int k)
{
if(k==) return x;
int tmp=Qpow(x,k/);
return k%?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod;
}
int C(int a,int b)
{
return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
}
bool SPJ()
{
if(!a||!b||n-<a+b-)
{puts(""); return false;}
if(n==)
{puts(""); return false;}
return true;
}
void Pre()
{
register int i,j;
fac[]=inv[]=,S[][]=;
for(i=;i<=;i++) fac[i]=1ll*fac[i-]*i%mod;
inv[]=Qpow(fac[],mod-);
for(i=;i;i--) inv[i]=1ll*inv[i+]*(i+)%mod;
for(i=;i<=;i++)
for(j=;j<=;j++)
S[i][j]=(S[i-][j-]+1ll*(i-)*S[i-][j]%mod)%mod;
}
int main()
{
Pre();
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&a,&b);
if(SPJ()) printf("%lld\n",1ll*C(a+b-,a-)*S[n-][a+b-]%mod);
}
return ;
}
解题:CF960G Bandit Blues & FJOI 2016 建筑师的更多相关文章
- CF960G Bandit Blues 第一类斯特林数、NTT、分治/倍增
传送门 弱化版:FJOI2016 建筑师 由上面一题得到我们需要求的是\(\begin{bmatrix} N - 1 \\ A + B - 2 \end{bmatrix} \times \binom ...
- CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】
题目链接 CF960G 题解 同FJOI2016只不过数据范围变大了 考虑如何预处理第一类斯特林数 性质 \[x^{\overline{n}} = \sum\limits_{i = 0}^{n}\be ...
- [CF960G] Bandit Blues
题意 给你三个正整数 \(n,a,b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,定义 \(B\) 为一个排列中是后缀最大值的数的个数,求长度为 \(n\) 的排列中满足 \(A = a ...
- CF960G Bandit Blues 分治+NTT(第一类斯特林数)
$ \color{#0066ff}{ 题目描述 }$ 给你三个正整数 \(n\),\(a\),\(b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,定义 \(B\) 为一个排列中是后缀最大 ...
- CF960G Bandit Blues(第一类斯特林数)
传送门 可以去看看litble巨巨关于第一类斯特林数的总结 设\(f(i,j)\)为\(i\)个数的排列中有\(j\)个数是前缀最大数的方案数,枚举最小的数的位置,则有递推式\(f(i,j)=f(i- ...
- [CF960G]Bandit Blues(第一类斯特林数+分治卷积)
Solution: 先考虑前缀,设 \(f(i, j)\) 为长度为 \(i\) 的排列中满足前缀最大值为自己的数有 \(j\) 个的排列数. 假设新加一个数 \(i+1\) 那么会有: \[ f ...
- CF960G Bandit Blues 第一类斯特林数+分治+FFT
题目传送门 https://codeforces.com/contest/960/problem/G 题解 首先整个排列的最大值一定是 \(A\) 个前缀最大值的最后一个,也是 \(B\) 个后缀最大 ...
- Luogu P4609 [FJOI2016]建筑师&&CF 960G Bandit Blues
考虑转化题意,我们发现其实就是找一个长度为\(n\)的全排列,使得这个排列有\(A\)个前缀最大值,\(B\)个后缀最大值,求方案数 我们考虑把最大值拎出来单独考虑,同时定义一些数的顺序排列为单调块( ...
- 【CF960G】Bandit Blues(第一类斯特林数,FFT)
[CF960G]Bandit Blues(第一类斯特林数,FFT) 题面 洛谷 CF 求前缀最大值有\(a\)个,后缀最大值有\(b\)个的长度为\(n\)的排列个数. 题解 完完全全就是[FJOI] ...
随机推荐
- Android设备管理器漏洞(转)
一.漏洞描述 目前被称为“史上最强Android木马”的病毒Backdoor.AndroidOS.Obad.a利用Android设备管理器漏洞使用户无法通过正常方式卸载.其实该漏洞早在去年底已被发现. ...
- 20155217《网络对抗》Exp05 MSF基础应用
20155217<网络对抗>Exp05 MSF基础应用 实践内容 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 一个主动攻击实践,如ms ...
- Vultr搭建SS服务
购买VPS VPS又叫虚拟服务器,相当于是讲物理服务器的资源进行虚拟划分然后分配给不同的用户使用. Vultr服务器按小时计费,最低0.004美元/h,算起来2.5美元/月,且destory掉服务器是 ...
- Mybatis初步详细配置
1.Mybatis所需包 下载地址:https://github.com/mybatis/mybatis-3/releases,其中log4j是日志包,mysql是数据库所需包,需自行下载 2.项目结 ...
- 学会查看Linux手册页(man文档)
区段1:用户指令区段2:系统调用区段3:程序库调用区段4:设备区段5:文件格式区段6:游戏区段7:杂项区段8:系统指令区段9:内核内部指令区段n:Tcl或Tk指令 如果记不清楚工具或者函数的完整名字, ...
- USART_GetITStatus和USART_GetFlagStatus的区别
USART_GetITStatus()和USART_GetFlagStatus()的区别 都是访问串口的SR状态寄存器,唯一不同是,USART_GetITStatus()会判断中断是否开启,如果没开启 ...
- GTK学习笔记————创建窗口
创建gtk1.c文件 代码 #include <gtk/gtk.h> int main (int argc, char *argv[]) { GtkWidget *window; gtk_ ...
- centos上部署mysql
本文记录整个安装的过程和跳进的坑,大家预祝我能从坑里爬出来吧 当前系统版本 开始我们的安装: 在安装之前查阅了部分资料,大体安装流程 yum -y install mysql yum -y insta ...
- PAT甲题题解-1038. Recover the Smallest Number (30)-排序/贪心,自定义cmp函数的强大啊!!!
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6789138.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- Beta任务项录入
今天PM把任务项整理写入TFS中,明天开始正式开发工作: