CF 848E(动态规划+分治NTT)
传送门:
http://codeforces.com/problemset/problem/848/E
题解:
假设0-n一定有一条边,我们得到了一个方案,那么显然是可以旋转得到其他方案的。
记最大的i满足i到i+n有一条边,那么旋转的方案数是n-i
考虑动态规划:
设\(g[i]\)表示i个点,只用相邻或隔一个去拼接的方案数。
转移显然有\(g[i]=g[i-2]+g[i-4]\)。
设\(f[i][0/1][0/1]\)表示1有连对面的,n+1有连对面的,2-n填,前面后面是否要伸出去的方案数。
那么显然有\(f[i][j][k]=g[i-1-j-k]*(i-1)^2\)。
设\(h[i][0/1]\)表示前i个确定了,第i个是连对面,后面是否伸出去。
显然有\(h[i][v]=\sum_{j=0}^{i-1}h[j][u]*f[i-j][u][v]\)
初值为:\(h[0][0]=1->ans+=?*h[?][0]\)
\(h[0][1]=1->ans+=?*h[?][1]\)
由于最后一段有长度的额外贡献,所以:
\(Ans=\sum_{i=0}^{n-1}h[i][u]*f[n-i][u][?]*(n-i)\)
这个东西显然可以分治NTT优化转移。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 998244353;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
typedef vector<ll> V;
#define pb push_back
#define si size()
namespace ntt {
const int nm = 131072;
ll a[nm], b[nm], w[nm]; int r[nm];
void build() {
for(int i = 1; i < nm; i *= 2) ff(j, 0, i)
w[i + j] = ksm(3, (mo - 1) / 2 / i * j);
}
void dft(ll *a, int n, int f) {
ff(i, 0, n) {
r[i] = r[i / 2] / 2 + (i & 1) * (n / 2);
if(i < r[i]) swap(a[i], a[r[i]]);
} ll b;
for(int i = 1; i < n; i *= 2) for(int j = 0; j < n; j += 2 * i)
ff(k, 0, i) b = a[i + j + k] * w[i + k], a[i + j + k] = (a[j + k] - b) % mo, a[j + k] = (a[j + k] + b) % mo;
if(f == -1) {
reverse(a + 1, a + n);
b = ksm(n, mo - 2);
ff(i, 0, n) a[i] = (a[i] + mo) * b % mo;
}
}
void fft(V &p, V &q) {
int p0 = p.si + q.si - 1;
int n = 1; while(n <= p0) n *= 2;
ff(i, 0, n) a[i] = b[i] = 0;
ff(i, 0, p.si) a[i] = p[i];
ff(i, 0, q.si) b[i] = q[i];
dft(a, n, 1); dft(b, n, 1);
ff(i, 0, n) a[i] = a[i] * b[i] % mo;
dft(a, n, -1);
p.resize(p0);
ff(i, 0, p0) p[i] = a[i];
}
}
V operator * (V a, V b) {
ntt :: fft(a, b);
return a;
}
const int N = 50005;
int n;
ll f[N][2][2], g[N], h[N][2], ans;
void dp(int x, int y, int m, int u, int v) {
V p, q;
p.resize(m - x + 1);
fo(i, x, m) p[i - x] = h[i][u];
q.resize(y - x + 1);
ff(i, 0, q.si) q[i] = f[i][u][v];
p = p * q;
fo(i, m + 1, y) h[i][v] = (h[i][v] + p[i - x]) % mo;
}
void dg(int x, int y) {
if(x == y) return;
int m = x + y >> 1;
dg(x, m);
fo(u, 0, 1) fo(v, 0, 1) dp(x, y, m, u, v);
dg(m + 1, y);
}
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
ntt :: build();
scanf("%d", &n);
g[0] = 1;
fo(i, 1, n) g[i] = ((i < 2 ? 0 : g[i - 2]) + (i < 4 ? 0 : g[i - 4])) % mo;
fo(i, 1, n) fo(j, 0, 1) fo(k, 0, 1)
f[i][j][k] = (i - 1 - j - k >= 0) ? g[i - 1 - j - k] * (i - 1) % mo * (i - 1) % mo: 0;
h[0][0] = 1;
dg(0, n - 1);
fo(i, 0, n - 1) fo(v, 0, 1) ans = (ans + h[i][v] * f[n - i][v][0] % mo * (n - i)) % mo;
memset(h, 0, sizeof h); h[0][1] = 1;
dg(0, n - 1);
fo(i, 0, n - 1) fo(v, 0, 1) ans = (ans + h[i][v] * f[n - i][v][1] % mo * (n - i)) % mo;
pp("%lld\n", ans);
}
CF 848E(动态规划+分治NTT)的更多相关文章
- 【BZOJ3992】序列统计(动态规划,NTT)
[BZOJ3992]序列统计(动态规划,NTT) 题面 BZOJ 题解 最裸的暴力 设\(f[i][j]\)表示前\(i\)个数,积在膜意义下是\(j\)的方案数 转移的话,每次枚举一个数,直接丢进去 ...
- CF 528D. Fuzzy Search NTT
CF 528D. Fuzzy Search NTT 题目大意 给出文本串S和模式串T和k,S,T为DNA序列(只含ATGC).对于S中的每个位置\(i\),只要中[i-k,i+k]有一个位置匹配了字符 ...
- #565. 「LibreOJ Round #10」mathematican 的二进制(期望 + 分治NTT)
题面 戳这里,题意简单易懂. 题解 首先我们发现,操作是可以不考虑顺序的,因为每次操作会加一个 \(1\) ,每次进位会减少一个 \(1\) ,我们就可以考虑最后 \(1\) 的个数(也就是最后的和) ...
- LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)
考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...
- 【BZOJ-3456】城市规划 CDQ分治 + NTT
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...
- CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】
题目链接 CF960G 题解 同FJOI2016只不过数据范围变大了 考虑如何预处理第一类斯特林数 性质 \[x^{\overline{n}} = \sum\limits_{i = 0}^{n}\be ...
- 洛谷5月月赛T30212 玩游戏 【分治NTT + 多项式求ln】
题目链接 洛谷T30212 题解 式子很容易推出来,二项式定理展开后对于\(k\)的答案即可化简为如下: \[k!(\sum\limits_{i = 0}^{k} \frac{\sum\limits_ ...
- loj2541 「PKUWC2018」猎人杀 【容斥 + 分治NTT】
题目链接 loj2541 题解 思路很妙啊, 人傻想不到啊 觉得十分难求,考虑容斥 由于\(1\)号可能不是最后一个被杀的,我们容斥一下\(1\)号之后至少有几个没被杀 我们令\(A = \sum\l ...
- hdu5279 YJC plays Minecraft 【分治NTT】
题目链接 hdu5279 题解 给出若干个完全图,然后完全图之间首尾相连并成环,要求删边使得两点之间路径数不超过\(1\),求方案数 容易想到各个完全图是独立的,每个完全图要删成一个森林,其实就是询问 ...
随机推荐
- nodejs 静态资源文件与登陆交互
server2.js var express=require('express'); var expressStatic=require('express-static'); var server=e ...
- Galaxy
Galaxy 在一维坐标轴上给出n个点,第i个点坐标为\(x_i\),现在你可以任意移动k个点的,最小化它们的方差,\(n\leq 50000\). 解 感觉以前写的太乱了,补一篇可以供快速阅读的题解 ...
- 揭秘阿里云EB级大数据计算引擎MaxCompute
日前,全球权威咨询与服务机构Forrester发布了<The Forrester WaveTM: Cloud Data Warehouse, Q4 2018>报告.这是Forrester ...
- apue.h报错问题
下载apue.3e后进入make,提示错误如下: collect2: error: exit status Makefile:: recipe for target 'badexit2' failed ...
- [Luogu P4178]Tree 题解(点分治+平衡树)
题目大意 给定一棵树,边带权,问有多少点对满足二者间距离$\leq K$,$n \leq 40000$. 题解 点分治专题首杀!$Jackpot!$ (本来看着题意比较简单想捡个软柿子捏,结果手断了… ...
- [NOIP模拟测试7]visit 题解(组合数学+CRT+Lucas定理)
Orz 因为有T的限制,所以不难搞出来一个$O(T^3)$的暴力dp 但我没试 据说有30分? 正解的话显然是组合数学啦 首先$n,m$可能为负,但这并没有影响, 我们可以都把它搞成正的 即都看作向右 ...
- Hadoop-HDFS的伪分布式和完全分布式集群搭建
Hadoop-HDFSHDFS伪分布式集群搭建步骤一.配置免密登录 ssh-keygen -t rsa1一句话回车到底 ssh-copy-id -i ~/.ssh/id_rsa.pub root@no ...
- NYOJ 737 (石子合并)
该题是一道DP题,核心思想如下: 某个区间一定是这个区间内的某两个子区间合成的(这两个子区间互补,即这两个区间加起来等于大区间), 所以我们枚举所有的情况,取个最大值即可.因为最初是从2堆石子开始无法 ...
- 关于C语言命令行参数问题
1 int main(int argc,char** argv) 参数: argc:命令行参数的个数 argv:保存命令行参数:argv[0]保存本程序自己的名称 现在自己只知道这些以后再有学习继续补 ...
- git分布式版本控制系统权威指南学习笔记(三):简单了解git对象、head以及sha1sum
文章目录 git对象(简单了解) 对象是存在哪里的? head和master分支 上面的hash值怎么来的? git对象(简单了解) 每次提交都有tree.parent.author.committe ...