题目大意

​  有\(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}\)有:

\[f_{i,j}=\sum_{k=0}^{j}\binom{j}{k} a_{i-1,k}\times f_{i-1,j-k}
\]

\[=\sum_{k=0}^{j}\frac{j!}{k!(j-k)!}a_{i-1,k}\times f_{i-1,j-k}
\]

\[=j!\sum_{k=0}^{j}\frac{a_{i-1,k}}{k!}\times \frac{f_{i-1,j-k}}{(j-k)!}
\]

​  观察到\(p=1004535809\)是一个NTT模数(原根为\(3\)),所以可以用NTT加速。

​  没了

​  时间复杂度:\(O(nk\log k)\)

题解2

​  FFT很明显会TLE

​  有一个公式:

\[m^n=\sum_{k=0}^m\binom{m}{k}S(n,k)k!
\]

​  后面两个东西很容易算,只用考虑第一个怎么求

​  这不就是个组合数吗

​  直接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 数学 第二类斯特林数的更多相关文章

  1. 【hdu4045】Machine scheduling(dp+第二类斯特林数)

    传送门 题意: 从\(n\)个人中选\(r\)个出来,但每两个人的标号不能少于\(k\). 再将\(r\)个人分为不超过\(m\)个集合. 问有多少种方案. 思路: 直接\(dp\)预处理出从\(n\ ...

  2. HDU - 4625 JZPTREE(第二类斯特林数+树DP)

    https://vjudge.net/problem/HDU-4625 题意 给出一颗树,边权为1,对于每个结点u,求sigma(dist(u,v)^k). 分析 贴个官方题解 n^k并不好转移,于是 ...

  3. bzoj 2159 Crash 的文明世界 && hdu 4625 JZPTREE ——第二类斯特林数+树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2159 学习材料:https://blog.csdn.net/litble/article/d ...

  4. P4827 [国家集训队] Crash 的文明世界(第二类斯特林数+树形dp)

    传送门 对于点\(u\),所求为\[\sum_{i=1}^ndis(i,u)^k\] 把后面那堆东西化成第二类斯特林数,有\[\sum_{i=1}^n\sum_{j=0}^kS(k,j)\times ...

  5. Codeforces Round #100 E. New Year Garland (第二类斯特林数+dp)

    题目链接: http://codeforces.com/problemset/problem/140/E 题意: 圣诞树上挂彩球,要求从上到下挂\(n\)层彩球.已知有\(m\)种颜色的球,球的数量不 ...

  6. 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)

    题意 ​ 题目链接:https://www.luogu.org/problem/P4827 ​ 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...

  7. BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)

    传送门 解题思路 比较有意思的一道数学题.首先\(n*k^2\)的做法比较好想,就是维护一个\(x^i\)这种东西,然后转移的时候用二项式定理拆开转移.然后有一个比较有意思的结论就是把求\(x^i\) ...

  8. [题解] LOJ 3300 洛谷 P6620 [省选联考 2020 A 卷] 组合数问题 数学,第二类斯特林数,下降幂

    题目 题目里要求的是: \[\sum_{k=0}^n f(k) \times X^k \times \binom nk \] 这里面出现了给定的多项式,还有组合数,这种题目的套路就是先把给定的普通多项 ...

  9. 【BZOJ2159】Crash的文明世界(第二类斯特林数,动态规划)

    [BZOJ2159]Crash的文明世界(第二类斯特林数,动态规划) 题面 BZOJ 洛谷 题解 看到\(k\)次方的式子就可以往二项式的展开上面考,但是显然这样子的复杂度会有一个\(O(k^2)\) ...

随机推荐

  1. Python Revisited Day 04 (控制结构与函数)

    目录 4.1 控制结构 4.1.1 条件分支 4.1.2 循环 4.2 异常处理 4.2.1 捕获与产生异常 4.2.2 自定义异常 4.3 自定义函数 Tips 参数默认值为可变时 危险 4.3.1 ...

  2. 砝码组合(dfs)

    砝码组合  题目内容:用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量.如果只有5个砝码,重量分别是1,3,9,27,81.则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两 ...

  3. Masonry练习详解

    添加约束的方式: 1.通过使用NSLayoutConstraints添加约束到约束数组中,之前必须设置translatesAutoresizingMaskIntoConstraints = NO,即取 ...

  4. 如何恢复Eclipse中被误删除的文件

    在使用Eclipse时,可能会不小心误删除一些文件,没关系,Eclipse有个非常强大的功能,能让这些误删除的文件恢复回来,下面就来介绍一下. 工具/原料   Eclipse Kepler 方法/步骤 ...

  5. Servlet 使用ServletContext共享数据,读取web.xml配置

    ServletContext对象 session和cookie,对于每一个请求用户来说,都是不同的,因为要保证隐私安全. 而有一些数据,可以让所有用户共享,此时就可以用ServletContext对象 ...

  6. Python3练习题 022:用递归函数反转字符串

    方法一 str = input('请输入若干字符:')   def f(x):     if x == -1:         return ''     else:         return s ...

  7. spring遇到的Error applying BeanValidation relational constraints

    spring3.1+hibernate4集成测试时遇到的问题: log4j:WARN No appenders could be found for logger (org.springframewo ...

  8. C++常用宏

    宏是由 #define 定义而来,在预处理阶段进行宏展开,它的格式是: #define N 2 + 2 // 仅仅是字符串替换 #define N (2 + 2) // 也是字符串 ,但是是(2 + ...

  9. POJ1108_Split Windows 解题报告

    Split Windows 题目链接:http://poj.org/problem?id=1108 题目大意: 给你一棵二叉树的先序遍历,有三种字符:|.-.A~Z,然后用窗口表示出来,|: 表示将当 ...

  10. 网络编程--使用UDP发送接收数据

    package com.zhangxueliang.udp; import java.io.IOException; import java.net.DatagramPacket; import ja ...