思路和任意模数FFT模板都来自 这里

看了一晚上那篇《再探快速傅里叶变换》还是懵得不行,可能水平还没到- -

只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太差了...

具体推导大概这样就可以了:

/*
HDU 6088 - Rikka with Rock-paper-scissors [ 任意模数FFT,数论 ] | 2017 Multi-University Training Contest 5
题意:
计算 3^n * ∑ [0<=i+j<=n] C(n, i) * C(n-i, j) * GCD(i,j)
N <= 1e5
分析:
利用 n = ∑ [d|n] φ(d)
化得:
3^n * ∑[1<=d<=n] d ∑ [0<=i+j<=n/d] C(n,i*d) * C(n-i*d, j*d)
之后枚举 d (以下略写 *d )
C(n,i*d) * C(n-i*d, j*d)
= n! * 1/(i!) * 1/(j!) * 1/(n-i-j)!
维护 f(i) = 1/i! 的卷积 g(k) = ∑ [i+j == k] * f(i) * f(j)
原式 = ∑[1<=i<=m] n! * g(k) * 1/(n-k)!
由于 gcd(0, 0) == 0
所以特判卷积的 g(0) 项不用加上
*/
#include <bits/stdc++.h>
using namespace std;
#define MOD mod
#define upmo(a,b) (((a)=((a)+(b))%MOD)<0?(a)+=MOD:(a))
typedef long long LL;
typedef double db;
const int N = 1e5+5;
int t, n;
LL inv[N], F[N], Finv[N], phi[N];
LL MOD;
namespace FFT_MO
{
const int FFT_MAXN = 1<<18;
const db PI = 4*atan(1.0);
struct cp
{
db a, b;
cp(db a_ = 0, db b_ = 0) {
a = a_, b = b_;
}
cp operator + (const cp& rhs) const {
return cp(a+rhs.a, b+rhs.b);
}
cp operator - (const cp& rhs) const {
return cp(a-rhs.a, b-rhs.b);
}
cp operator * (const cp& rhs) const {
return cp(a*rhs.a-b*rhs.b, a*rhs.b + b*rhs.a);
}
cp operator !() const{
return cp(a, -b);
}
}nw[FFT_MAXN+1], f[FFT_MAXN], g[FFT_MAXN], t[FFT_MAXN];
int bitrev[FFT_MAXN];
void fft_init()
{
int L = 0; while ((1<<L) != FFT_MAXN) L++;
for (int i = 1; i < FFT_MAXN; i++)
bitrev[i] = bitrev[i>>1]>>1 | ((i&1)<<(L-1));
for (int i = 0; i <= FFT_MAXN; i++)
nw[i] = cp((db)cosl(2*PI/FFT_MAXN*i), (db)sinl(2*PI/FFT_MAXN*i));
}
void dft(cp *a, int n, int flag = 1)
{
int d = 0; while ((1<<d)*n != FFT_MAXN) d++;
for (int i = 0; i < n; i++) if (i < (bitrev[i]>>d))
swap(a[i], a[bitrev[i]>>d]);
for (int l = 2; l <= n; l <<= 1)
{
int del = FFT_MAXN/l*flag;
for (int i = 0; i < n; i += l)
{
cp *le = a+i, *ri = a+i+(l>>1);
cp *w = flag==1 ? nw : nw+FFT_MAXN;
for (int k = 0; k < (l>>1); k++)
{
cp ne = *ri * *w;
*ri = *le - ne, *le = *le+ne;
le++, ri++, w += del;
}
}
}
if (flag != 1) for (int i = 0; i < n; i++) a[i].a /= n, a[i].b /= n;
}
void convo(LL *a, int n, LL *b, int m, LL *c)
{
for (int i = 0; i <= n+m; i++) c[i] = 0;
int N = 2; while (N <= n+m) N <<= 1;
for (int i = 0; i < N; i++)
{
LL aa = i <= n ? a[i] : 0, bb = i <= m ? b[i] : 0;
aa %= MOD, bb %= MOD;
f[i] = cp(db(aa>>15), db(aa&32767));
g[i] = cp(db(bb>>15), db(bb&32767));
}
dft(f, N), dft(g, N);
for (int i = 0; i < N; i++)
{
int j = i ? N-i : 0;
t[i] = ((f[i]+!f[j])*(!g[j]-g[i]) + (!f[j]-f[i])*(g[i]+!g[j])) * cp(0, 0.25);
}
dft(t, N, -1);
for (int i = 0; i <= n+m; i++) upmo(c[i], (LL(t[i].a+0.5))%MOD<<15);
for (int i = 0; i < N; i++)
{
int j = i? N-i : 0;
t[i] = (!f[j]-f[i])*(!g[j]-g[i])*cp(-0.25,0) + cp(0,0.25)*(f[i]+!f[j])*(g[i]+!g[j]);
}
dft(t, N, -1);
for (int i = 0; i <= n+m; i++)
upmo(c[i], LL(t[i].a+0.5)+(LL(t[i].b+0.5)%MOD<<30));
}
}
LL a[1<<18|1], b[1<<18|1], c[1<<18|1];
LL PowMod(LL a, LL m)
{
a %= MOD;
LL ret = 1;
while (m) {
if (m&1) ret = ret * a % MOD;
m >>= 1;
a = a*a % MOD;
}
return ret;
}
void GetEuler()
{
memset(phi, 0, sizeof(phi));
phi[1] = 1;
for (int i = 2; i < N; i++)
if (!phi[i])
for (int j = i; j < N; j += i)
{
if (!phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
void init(int n) {
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = (MOD - MOD/i) *inv[MOD % i] % MOD;
F[0] = Finv[0] = 1;
for (int i = 1; i <= n; i++) {
F[i] = F[i-1] * i % MOD;
Finv[i] = Finv[i-1] * inv[i] % MOD;
}
}
int main()
{
GetEuler();
scanf("%d", &t);
while (t--)
{
scanf("%d%lld", &n, &MOD);
init(n);
FFT_MO::fft_init();
LL ans = 0;
for (int d = 1; d <= n; d++)
{
int m = n/d;
for (int i = 0; i <= m; i++) b[i] = a[i] = Finv[i*d];
FFT_MO::convo(a, m, b, m, c);
for (int i = 0; i <= m; i++) c[i] = c[i] * Finv[n-i*d] % MOD;
LL sum = 0;
for (int i = 1; i <= m; i++) sum = (sum + c[i]) % MOD;
ans = (ans + sum * phi[d]) % MOD;
}
ans = ans * F[n] % MOD * PowMod(3, n) % MOD;
printf("%lld\n", ans);
}
}

  

HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5的更多相关文章

  1. 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 H题 Rock Paper Scissors Lizard Spock.(FFT字符串匹配)

    2018 ACM-ICPC 中国大学生程序设计竞赛线上赛:https://www.jisuanke.com/contest/1227 题目链接:https://nanti.jisuanke.com/t ...

  2. 2015多校联合训练赛 hdu 5308 I Wanna Become A 24-Point Master 2015 Multi-University Training Contest 2 构造题

    I Wanna Become A 24-Point Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 ...

  3. hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】

    题目链接 首先利用组合数学知识,枚举两人的总胜场数容易得到 这还不是卷积的形式,直接搞的话复杂度大概是O(n^2)的,肯定会TLE.但似乎和卷积有点像?想半天没想出来..多谢Q巨提醒,才知道可以用下面 ...

  4. SDUT 3568 Rock Paper Scissors 状压统计

    就是改成把一个字符串改成三进制状压,然后分成前5位,后5位统计, 然后直接统计 f[i][j][k]代表,后5局状压为k的,前5局比和j状态比输了5局的有多少个人 复杂度是O(T*30000*25*m ...

  5. HDU 6088 Rikka with Rock-paper-scissors(NTT+欧拉函数)

    题意 \(n\) 局石头剪刀布,设每局的贡献为赢的次数与输的次数之 \(\gcd\) ,求期望贡献乘以 \(3^{2n}\) ,定义若 \(xy=0\) 则,\(\gcd(x,y)=x+y\) 思路 ...

  6. FFT(Rock Paper Scissors Gym - 101667H)

    题目链接:https://vjudge.net/problem/Gym-101667H 题目大意:首先给你两个字符串,R代表石头,P代表布,S代表剪刀,第一个字符串代表第一个人每一次出的类型,第二个字 ...

  7. Gym - 101667H - Rock Paper Scissors FFT 求区间相同个数

    Gym - 101667H:https://vjudge.net/problem/Gym-101667H 参考:https://blog.csdn.net/weixin_37517391/articl ...

  8. Gym101667 H. Rock Paper Scissors

    将第二个字符串改成能赢对方时对方的字符并倒序后,字符串匹配就是卷积的过程. 那么就枚举字符做三次卷积即可. #include <bits/stdc++.h> struct Complex ...

  9. 【题解】CF1426E Rock, Paper, Scissors

    题目戳我 \(\text{Solution:}\) 考虑第二问,赢的局数最小,即输和平的局数最多. 考虑网络流,\(1,2,3\)表示\(Alice\)选择的三种可能性,\(4,5,6\)同理. 它们 ...

随机推荐

  1. Linux:删除一个目录下的所有文件,但保留一个指定文件

    面试题:删除一个目录下的所有文件,但保留一个指定文件 解答: 假设这个目录是/xx/,里面有file1,file2,file3..file10  十个文件 [root@oldboy xx]# touc ...

  2. MySQL create table语法中的key与index的区别

    在create table的语句中,key和index混淆在一起,官方手册中的解释是这样: KEY is normally a synonym for INDEX. The key attribute ...

  3. DPDK latencystats库使用方案

    初始化 注意务必调用 rte_metrics_init /* init latency stats */ /* @TODO should we remove this in product env? ...

  4. 利用axis调用webservice接口

    一.首先把wsdl文件放入eclipse中某个项目中的src目录下 二.右键弹出webservice,然后点击webservice菜单,选中genernator client ,选择axis生成Jav ...

  5. win 10 睡眠无法唤醒

    近日遇到win10系统睡眠后无法唤醒的问题,于是网上到处搜索解决办法,试了其中几个比如回退 Intel(R) Management Engine Interface 的版本.设置电源的睡眠选项以利用休 ...

  6. shiro系列一、认识shiro

    Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大 ...

  7. 计算机基础与python入门

    一.计算机.cpu与存储器 二.操作系统.编程语言及编写python.变量 三.数据类型.输入输出及基本运算 四.流程控制之if判断.while与for循环 一.计算机.cpu与存储器 1. 什么是编 ...

  8. Ubuntu18.04安装OpenCV4.1.0

    Ubuntu18.04安装OpenCV4.1.0 1.首先要安装依赖 sudo apt-get install build-essential \ cmake git libgtk2.0-dev pk ...

  9. PAT Basic 1064 朋友数 (20 分)

    如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”.例如 123 和 51 就是朋友数,因为 1+2+3 = 5+1 = 6,而 6 就是它们的朋友证号.给定 ...

  10. 图像处理---《Mat对象 与 IplImage对象》

    图像处理---<认识 Mat对象> Mat对象 与 IplImage对象 (1)Mat对象:OpenCV2.0之后引进的图像数据结构.自动分配内存.不存在内存泄漏的问题,是面向对象的数据结 ...