HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5
思路和任意模数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的更多相关文章
- 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 H题 Rock Paper Scissors Lizard Spock.(FFT字符串匹配)
2018 ACM-ICPC 中国大学生程序设计竞赛线上赛:https://www.jisuanke.com/contest/1227 题目链接:https://nanti.jisuanke.com/t ...
- 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 ...
- hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】
题目链接 首先利用组合数学知识,枚举两人的总胜场数容易得到 这还不是卷积的形式,直接搞的话复杂度大概是O(n^2)的,肯定会TLE.但似乎和卷积有点像?想半天没想出来..多谢Q巨提醒,才知道可以用下面 ...
- SDUT 3568 Rock Paper Scissors 状压统计
就是改成把一个字符串改成三进制状压,然后分成前5位,后5位统计, 然后直接统计 f[i][j][k]代表,后5局状压为k的,前5局比和j状态比输了5局的有多少个人 复杂度是O(T*30000*25*m ...
- HDU 6088 Rikka with Rock-paper-scissors(NTT+欧拉函数)
题意 \(n\) 局石头剪刀布,设每局的贡献为赢的次数与输的次数之 \(\gcd\) ,求期望贡献乘以 \(3^{2n}\) ,定义若 \(xy=0\) 则,\(\gcd(x,y)=x+y\) 思路 ...
- FFT(Rock Paper Scissors Gym - 101667H)
题目链接:https://vjudge.net/problem/Gym-101667H 题目大意:首先给你两个字符串,R代表石头,P代表布,S代表剪刀,第一个字符串代表第一个人每一次出的类型,第二个字 ...
- Gym - 101667H - Rock Paper Scissors FFT 求区间相同个数
Gym - 101667H:https://vjudge.net/problem/Gym-101667H 参考:https://blog.csdn.net/weixin_37517391/articl ...
- Gym101667 H. Rock Paper Scissors
将第二个字符串改成能赢对方时对方的字符并倒序后,字符串匹配就是卷积的过程. 那么就枚举字符做三次卷积即可. #include <bits/stdc++.h> struct Complex ...
- 【题解】CF1426E Rock, Paper, Scissors
题目戳我 \(\text{Solution:}\) 考虑第二问,赢的局数最小,即输和平的局数最多. 考虑网络流,\(1,2,3\)表示\(Alice\)选择的三种可能性,\(4,5,6\)同理. 它们 ...
随机推荐
- 【AtCoder】M-SOLUTIONS Programming Contest
M-SOLUTIONS Programming Contest A - Sum of Interior Angles #include <bits/stdc++.h> #define fi ...
- HDU 3461 思维+并查集
Code Lock 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3461 Problem Description A lock you use has ...
- linux下如何查看一个服务所在的安装路径?
当接手一个不是自己维护的linux服务器,我们常常会想要看看该服务器上是否安装了某个服务,这个服务安装的路径在哪? redis 是开发过程中常常会用到的一个服务,我这里就以这个服务为例,进行说明. 1 ...
- PHP内存管理-zendMM
ZendMM 是zend memory manager zendMM可以分为三层: 1.存储层 维护者不同体量内存的hash表,已提供堆层使用,负责向os申请和释放内存 2.堆层 PHP内存管理的核心 ...
- Unable to find optional library: org.apache.http.legacy 错误
在目录adt-bundle-windows-x86_64-20140702\sdk\platforms\android-20或者 C:\Users\Administrator\AppData\Loca ...
- 【01字典树】hdu-5536 Chip Factory
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5536 [题意] 求一个式子,给出一组数,其中拿出ai,aj,ak三个数,使得Max{ (ai+aj ...
- shell脚本查询某一目录的某一部分文件并且拷贝到其他目录(有则跳过没有则拷贝)
#!/bin/bash dir=`ls /root//*` for i in $dir do #basename 返回一个字符串参数的基本文件名称.(只剩下文件名除去路径名) a=`basename ...
- Prometheus Operator 自动发现和持久化
Prometheus Operator 自动发现和持久化 之前在 Prometheus Operator 下面自定义一个监控选项,以及自定义报警规则的使用.那么我们还能够直接使用前面课程中的自动发现功 ...
- Educational Codeforces Round 71 (Rated for Div. 2) Solution
A. There Are Two Types Of Burgers 题意: 给一些面包,鸡肉,牛肉,你可以做成鸡肉汉堡或者牛肉汉堡并卖掉 一个鸡肉汉堡需要两个面包和一个鸡肉,牛肉汉堡需要两个面包和一个 ...
- MySQL SELECT语法(四)UNION语法详解
源自MySQL 5.7 官方手册:13.2.9.3 UNION Syntax 一.UNION语法 UNION用于将多个SELECT语句的结果合并到一个结果集中. SELECT ... UNION [A ...