【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)\) ...
随机推荐
- C\S 架构 DNS服务器 交换机 路由器
------------------------只有不快的斧,没有劈不开的柴;只有想不到的人,没有做不到的事.想干总会有办法,不想干总会有理由!# -------------------------- ...
- HDU - 1698 线段树区间修改,区间查询
这就是很简单的基本的线段树的基本操作,区间修改,区间查询,对区间内部信息打上laze标记,然后维护即可. 我自己做的时候太傻逼了...把区间修改写错了,对给定区间进行修改的时候,mid取的是节点的左右 ...
- Vue Router 路由实现原理
一.概念 通过改变 URL,在不重新请求页面的情况下,更新页面视图. 二.实现方式 更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式: 1.Hash ...
- 百度地图支持https
百度地图SDK, 支持https <script src="http://api.map.baidu.com/api?v=3.0&ak=nbnttGGI6lilllgy2zn ...
- PAT L2-007 家庭房产
https://pintia.cn/problem-sets/994805046380707840/problems/994805068539215872 给定每个人的家庭成员和其自己名下的房产,请你 ...
- Git Gerrit Code Review
Gerrit Code Review | Gerrit Code Reviewhttps://www.gerritcodereview.com/
- Non-Volatile Register 非易失性寄存器 调用约定对应寄存器使用
非易失性寄存器(Non-volatile register)是它的内容必须通过子程序调用被保存的一个寄存器.如果一个程序改变了一个非易失性寄存器的值,它必须保存在改变这个寄存器之前堆栈中保存旧的值和在 ...
- ubuntu使用squid搭建代理
安装squid //检查是否安装squid which squid // apt update sudo apt install squid 配置squid的配置文件squid.conf //备份sq ...
- window端编码到Linux允许脚本 笔记
昨天升级一个服务,发现没有现成的启动脚本.就随手写了一个,一运行发现不行.竟然报错说找不到文件,No such file or directory [nohup: cannot run command ...
- 5 Http请求中文乱码处理
java 乱码分很多种,这里主要研究解决http请求中出现乱码的情况. http请求出现中文乱码的主要原因:发送方与接收方编码不一致,服务器默认支持的编码与web应用不一致,如:tomcat 是国外程 ...