题目链接

https://atcoder.jp/contests/agc019/tasks/agc019_e

题解

tourist的神仙E题啊做不来做不来……这题我好像想歪了啊= =……

首先我们可以考虑,什么样的操作序列才是合法的?

有用的位置只有两种,一种是两个序列在这个位置上都是1, 称作11型,另一种是一个0一个1, 称作01型。设两种位置分别有\(A\)个和\(2B\)个。

考虑一个操作序列,交换两个11型相当于没交换,每个11型只会被交换两次,每个01型只会被交换一次。这也就是说,如果我们从shuffle之后的\(a_i\)向\(b_i\)连边,那么形成的图一定是若干个环加上\(m\)条链,链的开头结尾都是01型,中间是11型。对于链来说,上面操作的顺序必须固定;对于环来说,上面操作的顺序可以任意。

下面有两种处理方式。

做法一

设\(dp[i][j]\)表示把\(j\)个无标号的11型放到\(i\)条链中,可得DP式: \(dp[i][j]=\sum_{k\ge 0}\frac{dp[i-1][j-k]}{(k+1)!}\), 其中分母的含义是链上\((k+1)\)个点顺序固定,最后的答案是\(A!B!(A+B)!\sum^A_{i=0}dp[B][i]\). \((A+B)!\)表示将边随意排序,\(A!B!\)表示11型和01型点之间是有标号的。

时间复杂度\(O(n^3)\).

但是我们发现这个DP就相当于在给多项式\(\sum_{n\ge 0}\frac{1}{(n+1)!}x^n\)进行幂运算,于是用多项式快速幂加速即可,时间复杂度\(O(n\log^2n)\)或\(O(n\log n)\).

做法二

有没有聪明一点的做法?有!

设\(dp[i][j]\)表示目前一共放了\(i\)个11型和\(j\)个01型链(考虑已经放了的元素的标号,但是每次仅仅是往右添加),我们强行转移!

\(dp[i][j]=j^2\times dp[i][j-1]+ij\times dp[i-1][j]\)

前一个式子是要加一个新的01型链,选两个01型;后一个式子是要选一个链,再把这条链的结尾端点任意扩展一个位置。

答案就是\(\sum_{k}{A\choose k}\times f[k][B]\times ((A-k)!)^2\times {A+B\choose A-k}\), 其中\(A+B\choose A-k\)是选出位置,\(A\choose k\)是选出编号,\(((A-k)!)^2\)是求出组成环的方案数。

时间复杂度\(O(n^2)\), 可以通过。

但是我们发现这个DP还可以用多项式优化!

令\(g[i][j]=\frac{dp[i][j]}{(j!)^2i!}\), 显然有\(g[i][j]=g[i][j-1]+j\times g[i-1][j]\)

然后这个使用NE Lattice Path的方式来理解,就是从\((0,0)\)走到\((i,j)\),每往上走一次路径权值乘上横坐标,求所有路径权值和。

考虑另一种DP,枚举在第\(i\)列走几步,那么发现第\(i\)列的生成函数就是\(\frac{1}{1-ix}\), 然后答案就是所有列生成函数之积

于是可以分治NTT+多项式求逆计算,时间复杂度\(O(n\log^2n)\).

代码

做法二\(O(n^2)\)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
#include<cstring>
#define llong long long
using namespace std; const int N = 2e4;
const int P = 998244353;
const llong INV2 = 499122177;
llong fact[N+3],finv[N+3]; llong quickpow(llong x,llong y)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
cur = cur*cur%P;
}
return ret;
}
llong mulinv(llong x) {return quickpow(x,P-2);}
llong comb(llong x,llong y) {return x<0||y<0||x<y ? 0ll : fact[x]*finv[y]%P*finv[x-y]%P;} int n,a,b;
char s[N+3],t[N+3];
llong dp[2][N+3]; int main()
{
fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;
finv[N] = quickpow(fact[N],P-2); for(int i=N-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
scanf("%s%s",s+1,t+1); n = strlen(s+1);
for(int i=1; i<=n; i++)
{
if(s[i]=='1' && t[i]=='1') {a++;}
else if(s[i]^t[i]) {b++;}
}
b>>=1;
int cur = 0,prv = 1;
dp[0][0] = 1ll;
for(int j=1; j<=b; j++)
{
cur^=1; prv^=1;
dp[cur][0] = dp[prv][0]*j*j%P;
for(int i=1; i<=a; i++)
{
dp[cur][i] = (dp[prv][i]*j*j+dp[cur][i-1]*i*j)%P;
// printf("dp[%d][%d]=%lld\n",i,j,dp[cur][i]);
}
}
llong ans = 0ll;
for(int k=0; k<=a; k++)
{
ans = (ans+dp[cur][k]*comb(a,k)%P*fact[a-k]%P*fact[a-k]%P*comb(a+b,a-k))%P;
// printf("k%d ans%lld\n",k,ans);
}
printf("%lld\n",ans);
return 0;
}

AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)的更多相关文章

  1. 【XSY2612】Comb Avoiding Trees 生成函数 多项式求逆 矩阵快速幂

    题目大意 本题的满二叉树定义为:不存在只有一个儿子的节点的二叉树. 定义一棵满二叉树\(A\)包含满二叉树\(B\)当且经当\(A\)可以通过下列三种操作变成\(B\): 把一个节点的两个儿子同时删掉 ...

  2. FFT模板 生成函数 原根 多项式求逆 多项式开根

    FFT #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> ...

  3. bzoj 3456 城市规划——分治FFT / 多项式求逆 / 多项式求ln

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3456 分治FFT: 设 dp[ i ] 表示 i 个点时连通的方案数. 考虑算补集:连通的方 ...

  4. 【BZOJ3456】轩辕朗的城市规划 无向连通图计数 CDQ分治 FFT 多项式求逆 多项式ln

    题解 分治FFT 设\(f_i\)为\(i\)个点组成的无向图个数,\(g_i\)为\(i\)个点组成的无向连通图个数 经过简单的推导(枚举\(1\)所在的连通块大小),有: \[ f_i=2^{\f ...

  5. NTT+多项式求逆+多项式开方(BZOJ3625)

    定义多项式$h(x)$的每一项系数$h_i$,为i在c[1]~c[n]中的出现次数. 定义多项式$f(x)$的每一项系数$f_i$,为权值为i的方案数. 通过简单的分析我们可以发现:$f(x)=\fr ...

  6. 2019.01.01 bzoj3625:小朋友和二叉树(生成函数+多项式求逆+多项式开方)

    传送门 codeforces传送门codeforces传送门codeforces传送门 生成函数好题. 卡场差评至今未过 题意简述:nnn个点的二叉树,每个点的权值KaTeX parse error: ...

  7. 【BZOJ3625】【codeforces438E】小朋友和二叉树 生成函数+多项式求逆+多项式开根

    首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...

  8. [Codeforces438E][bzoj3625] 小朋友和二叉树 [多项式求逆+多项式开根]

    题面 传送门 思路 首先,我们把这个输入的点的生成函数搞出来: $C=\sum_{i=0}^{lim}s_ix^i$ 其中$lim$为集合里面出现过的最大的数,$s_i$表示大小为$i$的数是否出现过 ...

  9. P6295-有标号 DAG 计数【多项式求逆,多项式ln】

    正题 题目链接:https://www.luogu.com.cn/problem/P6295 题目大意 求所有\(n\)个点的弱联通\(DAG\)数量. \(1\leq n\leq 10^5\) 解题 ...

随机推荐

  1. Open API

    OAuth和SSO都可以做统一认证登录,但是OAuth的流程比SSO复杂.SSO只能做用户的认证登录,OAuth不仅能做用户的认证登录,开可以做open api开放更多的用户资源. Open API即 ...

  2. 区间dp 括号匹配问题

    这道题目能用区间dp来解决,是因为一个大区间的括号匹配数是可以由小区间最优化选取得到(也就是满足最优子结构) 然后构造dp 既然是区间类型的dp 一般用二维 我们定义dp[i][j] 表示i~j这个区 ...

  3. 【原创】大叔经验分享(70)marathon重启app后一直处于waiting状态

    marathon重启app后一直处于waiting状态,查看marathon日志 # journalctl -u marathon -f 有如下日志: Jun 14 12:58:38 DataOne- ...

  4. luogu题解P2502[HAOI2006]旅行--最小生成树变式

    题目链接 https://www.luogu.org/problemnew/show/P2502 分析 一个很\(naive\)的做法是从\(s\)到\(t\)双向BFS这当然会TLE 这时我就有个想 ...

  5. CF516D Drazil and Morning Exercise

    cf luogu 首先每个点到最远点的距离可以预处理出来,这个距离显然是这个点到树直径两端点的最大值.把那个距离记为\(d_i\),然后从小到大枚举\(d_i\),并强制它为最大的\(d_i\),那么 ...

  6. 【科创人·独家】连续创业者高春辉的这六年:高强度投入打造全球领先的IP数据库

    您能看到:高春辉的创业观,IPIP.NET半程复盘及未来规划,连续创业的体验,小众产品趣事 您看不到:往年创业的回顾,技术干货,受制于篇幅忍痛割舍的精彩观点 文末彩蛋:<与雷军的分歧并非否定电商 ...

  7. js判断浏览器内核如果是ie弹出提示非ie不进行任何操作

    如上做一个弹出框针对ie兼容 // 获取IE版本 function IEVersion() { // 取得浏览器的userAgent字符串 var userAgent = navigator.user ...

  8. 剖析Vue之双向数据绑定

    vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调 ...

  9. IntelliJ IDEA(Community版本)本地模式的下载、安装及其使用

    对于初学者来说可以先使用免费的社区版本练练手. ideaIC-2017.3.5——>社区版 ideaIU-2017.3.5——>旗舰版 一.IntelliJ IDEA(Community版 ...

  10. mybatis-03

    mybatis-03 1.mybatis的别名[两种]在MyBatis中可以为变量类型定义别名.简化映射文件的定义,在核心配置文件中定义的别名.别名应用:MyBatis框架先将resultType定义 ...