【XSY1519】彩灯节 DP 数学 第二类斯特林数
题目大意
有\(n\)盏灯,\(m\)个限制。每个限制\((x,y)\)表示第\(x\)盏灯与第\(y\)盏灯之间必须且只能亮一盏。
记一种情况\(x\)亮着的灯的数量为\(f_x\),求\(\sum {(f_x)}^k\)
\(n\leq 200000,k\leq 100\)
题解
我们先把整张图黑白染色。
如果不是二分图就无解。
我们发现两个不同的联通分量的灯的状态是没有关系的。
我们可以考虑DP:
\(f_{i,j}=\)前\(i\)个联通分量中亮的彩灯个数的\(j\)次方和
\(a_{i,j}=\)第\(i\)个联通分量中亮的彩灯个数的\(j\)次方和
根据二项式定理\({(a+b)}^n=\sum_{i=0}^n\binom nia^ib^{n-i}\)有:
\]
\]
\]
观察到\(p=1004535809\)是一个NTT模数(原根为\(3\)),所以可以用NTT加速。
没了
时间复杂度:\(O(nk\log k)\)
题解2
FFT很明显会TLE
有一个公式:
\]
后面两个东西很容易算,只用考虑第一个怎么求
这不就是个组合数吗
直接DP就行了。
时间复杂度:\(O(nk)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll p=1004535809;
ll fp(ll a,ll b)
{
ll s=1;
while(b)
{
if(b&1)
s=s*a%p;
a=a*a%p;
b>>=1;
}
return s;
}
namespace ntt
{
int N;
ll w1[500010];
ll w2[500010];
int rev[500010];
void get(int n)
{
N=1;
while(N<n)
N<<=1;
int i;
for(i=2;i<=N;i++)
{
w1[i]=fp(3,(p-1)/i);
w2[i]=fp(w1[i],p-2);
}
rev[0]=0;
for(i=1;i<N;i++)
rev[i]=(rev[i>>1]>>1)|(i&1?N>>1:0);
}
void ntt(ll *a,int t)
{
int i,j,k;
ll u,v,w,wn;
for(i=0;i<N;i++)
if(rev[i]<i)
swap(a[i],a[rev[i]]);
for(i=2;i<=N;i<<=1)
{
wn=t?w1[i]:w2[i];
for(j=0;j<N;j+=i)
{
w=1;
for(k=j;k<j+i/2;k++)
{
u=a[k];
v=a[k+i/2]*w%p;
a[k]=(u+v)%p;
a[k+i/2]=(u-v+p)%p;
w=w*wn%p;
}
}
}
if(!t)
{
ll inv=fp(N,p-2);
for(i=0;i<N;i++)
a[i]=a[i]*inv%p;
}
}
}
struct list
{
int v[500010];
int t[500010];
int h[200010];
int n;
list()
{
n=0;
memset(h,0,sizeof h);
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
list l;
int vis[200010];
void failed()
{
putchar('0');
exit(0);
}
int s1,s2;
void dfs(int x,int fa,int v)
{
vis[x]=v;
if(v)
s1++;
else
s2++;
int i;
for(i=l.h[x];i;i=l.t[i])
if(l.v[i]!=fa)
{
if(vis[l.v[i]]==-1)
dfs(l.v[i],x,v^1);
else if(vis[l.v[i]]==vis[x])
failed();
}
}
ll f[500010];
ll a[500010];
int n,m,k;
ll fac[500010];
int main()
{
freopen("bulb.in","r",stdin);
freopen("bulb.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
ntt::get(2*(k+1));
int i,j,x,y;
fac[0]=1;
for(i=1;i<=1000;i++)
fac[i]=fac[i-1]*i%p;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
l.add(x,y);
l.add(y,x);
}
memset(vis,-1,sizeof vis);
f[0]=1;
for(i=1;i<=n;i++)
if(vis[i]==-1)
{
s1=s2=0;
dfs(i,0,1);
for(j=0;j<=k;j++)
a[j]=(fp(s1,j)+fp(s2,j))%p;
for(j=k+1;j<ntt::N;j++)
a[j]=f[j]=0;
for(j=0;j<ntt::N;j++)
{
ll inv=fp(fac[j],p-2);
a[j]=a[j]*inv%p;
f[j]=f[j]*inv%p;
}
ntt::ntt(a,1);
ntt::ntt(f,1);
for(j=0;j<ntt::N;j++)
f[j]=f[j]*a[j]%p;
ntt::ntt(f,0);
for(j=0;j<=k;j++)
f[j]=f[j]*fac[j]%p;
// do something here ...
}
printf("%lld\n",f[k]);
return 0;
}
代码2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll p=1004535809;
ll fp(ll a,ll b)
{
ll s=1;
while(b)
{
if(b&1)
s=s*a%p;
a=a*a%p;
b>>=1;
}
return s;
}
struct list
{
int v[500010];
int t[500010];
int h[200010];
int n;
list()
{
n=0;
memset(h,0,sizeof h);
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
list l;
int vis[200010];
void failed()
{
putchar('0');
exit(0);
}
int s1,s2;
void dfs(int x,int fa,int v)
{
vis[x]=v;
if(v)
s1++;
else
s2++;
int i;
for(i=l.h[x];i;i=l.t[i])
if(l.v[i]!=fa)
{
if(vis[l.v[i]]==-1)
dfs(l.v[i],x,v^1);
else if(vis[l.v[i]]==vis[x])
failed();
}
}
int n,m,k;
ll fac[500010];
ll f[510];
ll f2[510];
ll f1[510];
void dp1()
{
int i;
for(i=k;i>=1;i--)
f1[i]=(f1[i]+f1[i-1])%p;
}
void dp2()
{
int i;
for(i=k;i>=1;i--)
f2[i]=(f2[i]+f2[i-1])%p;
}
ll s[510][510];
int main()
{
// freopen("bulb.in","r",stdin);
// freopen("bulb4.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
int i,j,x,y;
fac[0]=1;
for(i=1;i<=1000;i++)
fac[i]=fac[i-1]*i%p;
s[0][0]=1;
for(i=1;i<=100;i++)
{
s[i][0]=0;
for(j=1;j<=100;j++)
s[i][j]=(s[i-1][j-1]+s[i-1][j]*j%p)%p;
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
l.add(x,y);
l.add(y,x);
}
memset(vis,-1,sizeof vis);
f[0]=1;
for(i=1;i<=n;i++)
if(vis[i]==-1)
{
s1=s2=0;
dfs(i,0,1);
for(j=0;j<=k;j++)
f1[j]=f2[j]=f[j];
for(j=1;j<=s1;j++)
dp1();
for(j=1;j<=s2;j++)
dp2();
for(j=0;j<=k;j++)
f[j]=(f1[j]+f2[j])%p;
}
ll ans=0;
for(i=0;i<=k;i++)
ans=(ans+f[i]*s[k][i]%p*fac[i]%p)%p;
printf("%lld\n",ans);
return 0;
}
【XSY1519】彩灯节 DP 数学 第二类斯特林数的更多相关文章
- 【hdu4045】Machine scheduling(dp+第二类斯特林数)
传送门 题意: 从\(n\)个人中选\(r\)个出来,但每两个人的标号不能少于\(k\). 再将\(r\)个人分为不超过\(m\)个集合. 问有多少种方案. 思路: 直接\(dp\)预处理出从\(n\ ...
- HDU - 4625 JZPTREE(第二类斯特林数+树DP)
https://vjudge.net/problem/HDU-4625 题意 给出一颗树,边权为1,对于每个结点u,求sigma(dist(u,v)^k). 分析 贴个官方题解 n^k并不好转移,于是 ...
- bzoj 2159 Crash 的文明世界 && hdu 4625 JZPTREE ——第二类斯特林数+树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2159 学习材料:https://blog.csdn.net/litble/article/d ...
- P4827 [国家集训队] Crash 的文明世界(第二类斯特林数+树形dp)
传送门 对于点\(u\),所求为\[\sum_{i=1}^ndis(i,u)^k\] 把后面那堆东西化成第二类斯特林数,有\[\sum_{i=1}^n\sum_{j=0}^kS(k,j)\times ...
- Codeforces Round #100 E. New Year Garland (第二类斯特林数+dp)
题目链接: http://codeforces.com/problemset/problem/140/E 题意: 圣诞树上挂彩球,要求从上到下挂\(n\)层彩球.已知有\(m\)种颜色的球,球的数量不 ...
- 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)
题意 题目链接:https://www.luogu.org/problem/P4827 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...
- BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)
传送门 解题思路 比较有意思的一道数学题.首先\(n*k^2\)的做法比较好想,就是维护一个\(x^i\)这种东西,然后转移的时候用二项式定理拆开转移.然后有一个比较有意思的结论就是把求\(x^i\) ...
- [题解] LOJ 3300 洛谷 P6620 [省选联考 2020 A 卷] 组合数问题 数学,第二类斯特林数,下降幂
题目 题目里要求的是: \[\sum_{k=0}^n f(k) \times X^k \times \binom nk \] 这里面出现了给定的多项式,还有组合数,这种题目的套路就是先把给定的普通多项 ...
- 【BZOJ2159】Crash的文明世界(第二类斯特林数,动态规划)
[BZOJ2159]Crash的文明世界(第二类斯特林数,动态规划) 题面 BZOJ 洛谷 题解 看到\(k\)次方的式子就可以往二项式的展开上面考,但是显然这样子的复杂度会有一个\(O(k^2)\) ...
随机推荐
- 01 Django REST Framework 介绍
01-Django REST Framework的介绍 Django REST框架是一个用于构建Web API的强大而灵活的工具包. 您可能希望使用REST框架的一些原因: 1. Web可浏览API对 ...
- Python-sys模块-61
sys 模块:和Python解释器打交道的模块 sys模块是与python解释器交互的一个接口 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退 ...
- 软工网络15团队作业8——Beta阶段敏捷冲刺
Deadline: 2018-5-31 22:00PM,以博客提交至班级博客时间为准 根据以下要求: (1)在敏捷冲刺前发布一篇博客,作为beta版敏捷冲刺的开始, (2)同时,团队在日期区间[5.2 ...
- JEECG框架中使用Flash版本Uploadify,在Chrome版本号70下无法启动的解决办法
感谢文章:https://www.cnblogs.com/zinan/p/6902427.html 单独打开IFRAME中的页面 点击导航栏的<不安全> 再刷新单独IFRAME的页面,就可 ...
- 便捷的ajax请求
为什么要做这个呢?如果后端给的数据不单有JSON字符串,还有对象呢?这个时候我们就要每个都处理(JSON.parse).万一后端又改了,所有都是对象呢?如此一来我们就需要对我们的ajax进行封装. 这 ...
- 快速理解Git结构
git pull:拉取远程服务器最新代码到本地(会自动merge) git add:将本地代码添加到暂存区 git commit:将暂存区的所有内容提交到当前分支(git会自动为我们创建第一个分支 ...
- [转帖]BRD、MRD 和 PRD
来源: https://www.zhihu.com/question/19655491 BRD 商业需求文档 Business Requirement Document MRD 市场需求文档 Mark ...
- day 7-8 协程
不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去调 只要你用并发,就会有锁的问题,但是你不能一直去自己加锁吧那么我们 ...
- Linux安装mysql5.6
安装mysql5.6https://www.cnblogs.com/wangdaijun/p/6132632.html
- sed 双引号 单引号的区别
a="abcd" b="abc" sed -i '/$a/ s/$/$b/' test.a 我想在test.a中匹配以”abcd“开头的行,然后在行尾加入”ab ...