hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】
首先利用组合数学知识,枚举两人的总胜场数容易得到
这还不是卷积的形式,直接搞的话复杂度大概是O(n^2)的,肯定会TLE。但似乎和卷积有点像?想半天没想出来。。多谢Q巨提醒,才知道可以用下面这个公式进行转化
最后,化得的公式为
另外注意,上式右边是一个卷积的形式,但是,所得和的第一项是不需要加上的(不过图中公式没有体现)。结合实际意义大概就是,i==0&&j==0时,gcd(i,j)不存在约数d,虽然0可以被任意正整数整除 & 第一项不为0
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define upmo(a,b) (((a)=((a)+(b))%mod)<0?(a)+=mod:(a)) // 相加后取模 int n,mod; namespace FFT_MO //前面需要有 mod(1e8~1e9级别),upmo(a,b) 的定义
{
const int FFT_MAXN=<<;
const db pi=.14159265358979323846264338327950288L;
struct cp
{
db a,b;
cp(double a_=,double b_=)
{
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+],f[FFT_MAXN],g[FFT_MAXN],t[FFT_MAXN]; //a<->f,b<->g,t<~>c
int bitrev[FFT_MAXN]; void fft_init() //初始化 nw[],bitrev[]
{
int L=;while((<<L)!=FFT_MAXN) L++;
for(int i=;i<FFT_MAXN;i++) bitrev[i]=bitrev[i>>]>>|((i&)<<(L-));
for(int i=;i<=FFT_MAXN;i++) nw[i]=cp((db)cosl(*pi/FFT_MAXN*i),(db)sinl(*pi/FFT_MAXN*i));
} // n已保证是2的整数次幂
// flag=1:DFT | flag=-1: IDFT
void dft(cp *a,int n,int flag=)
{
int d=;while((<<d)*n!=FFT_MAXN) d++;
for(int i=;i<n;i++) if(i<(bitrev[i]>>d))
swap(a[i],a[bitrev[i]>>d]); // NOTICE!
for(int l=;l<=n;l<<=)
{
int del=FFT_MAXN/l*flag; // 决定 wn是在复平面是顺时针还是逆时针变化,以及变化间距
for(int i=;i<n;i+=l) // ?????????????????
{
cp *le=a+i,*ri=a+i+(l>>); // ?????????????????
cp *w=flag==? nw:nw+FFT_MAXN; // 确定wn的起点
for(int k=;k<(l>>);k++)
{
cp ne=*ri * *w;
*ri=*le-ne,*le=*le+ne;
le++,ri++,w+=del;
}
}
}
if(flag!=) for(int i=;i<n;i++) a[i].a/=n,a[i].b/=n;
} // convo(a,n,b,m,c) a[0..n]*b[0..m] -> c[0..n+m]
void convo(LL *a,int n,LL *b,int m,LL *c)
{
for(int i=;i<=n+m;i++) c[i]=;
int N=;while(N<=n+m) N<<=; // N是c扩展后的长度
for(int i=;i<N;i++) //扩展 a[],b[] ,存入f[],g[],注意取模
{
LL aa=i<=n?a[i]:,bb=i<=m? b[i]:;
aa%=mod,bb%=mod;
f[i]=cp(db(aa>>),db(aa&));
g[i]=cp(db(bb>>),db(bb&));
}
dft(f,N),dft(g,N);
for(int i=;i<N;i++) // 频域求积 // ?????????????????
{
int j=i? N-i:;
t[i]=((f[i]+!f[j])*(!g[j]-g[i])+(!f[j]-f[i])*(g[i]+!g[j]))*cp(,0.25);
}
dft(t,N,-);
for(int i=;i<=n+m;i++) upmo(c[i],(LL(t[i].a+0.5))%mod<<);
for(int i=;i<N;i++) // 频域求积 // ?????????????????
{
int j=i? N-i:;
t[i]=(!f[j]-f[i])*(!g[j]-g[i])*cp(-0.25,)+cp(,0.25)*(f[i]+!f[j])*(g[i]+!g[j]);
}
dft(t,N,-);
for(int i=;i<=n+m;i++) upmo(c[i],LL(t[i].a+0.5)+(LL(t[i].b+0.5)%mod<<));
}
} //==============预处理阶乘及阶乘逆元============== LL qpow(LL x,LL n) //求x^n%mod
{
LL ret=;
for(; n; n>>=)
{
if(n&) ret=ret*x%mod;
x=x*x%mod;
}
return ret;
}
LL inv(LL x)
{
return qpow(x,mod-);
}
const LL M=1e5+;
LL fac[M+]; //阶乘
LL inv_of_fac[M+]; //阶乘的逆元
void init_fac()
{
fac[]=;
for(int i=; i<=M; i++)
fac[i]=fac[i-]*i%mod;
inv_of_fac[M]=qpow(fac[M],mod-);
for(int i=M-; i>=; i--)
inv_of_fac[i]=inv_of_fac[i+]*(i+)%mod;
}
//================================================ //===================phi(x)打表=================== const int maxn=;
int phi[maxn+];
void init_phi()
{
memset(phi,,sizeof(phi)); //初始化为0
phi[]=;
for(int i=; i<=maxn; i++)
{
if(!phi[i]) //当i是质数时
for(int j=i; j<=maxn; j+=i) //筛选所有因子为i的数
{
if(!phi[j]) phi[j]=j; //若未赋值过,先初始化
phi[j]=phi[j]/i*(i-); //i是质因数(1-1/i)=(i-1)/i,先除再乘是为了防止越界。
}
}
}
//================================================ LL a[<<|],b[<<|],c[<<|]; int main()
{
init_phi();FFT_MO::fft_init(); //=============debug============== // int n,m;
// mod=1e9+7;
// while(cin>>n>>m)
// {
// for(int i=0;i<=n;i++) cin>>a[i];
// for(int i=0;i<=m;i++) cin>>b[i];
// FFT_MO::convo(a,n,b,m,c);
// for(int i=0;i<=n+m;i++)
// cout<<c[i]<<' ';
// puts("");
// } //================================
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&mod);
init_fac();
LL ans=;
for(int d=;d<=n;d++)
{
int N=n/d;
for(int i=;i<=N;i++) a[i]=b[i]=inv_of_fac[i*d];
FFT_MO::convo(a,N,b,N,c);
LL temp=;
for(int i=;i<=N;i++) temp=(temp+c[i]*inv_of_fac[n-i*d])%mod;
ans=(ans+temp*phi[d])%mod;
}
ans=ans*fac[n]%mod*qpow(,n)%mod;
printf("%lld\n",ans);
}
}
hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】的更多相关文章
- hdu多校第五场1004 (hdu6627) equation 1 计算几何
题意: 给你一个C,再给你n组a,b,让你求x取什么值的时候,$ \sum_{i=1}^n |a_i*x+b_i| =C $,要求求出解的个数,并用最简分数从小到大表示,如果有无穷多解,输出-1. 题 ...
- HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5
思路和任意模数FFT模板都来自 这里 看了一晚上那篇<再探快速傅里叶变换>还是懵得不行,可能水平还没到- - 只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太 ...
- 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 H题 Rock Paper Scissors Lizard Spock.(FFT字符串匹配)
2018 ACM-ICPC 中国大学生程序设计竞赛线上赛:https://www.jisuanke.com/contest/1227 题目链接:https://nanti.jisuanke.com/t ...
- 2017多校第7场 HDU 6128 Inverse of sum 推公式或者二次剩余
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6128 题意:给你n个数,问你有多少对i,j,满足i<j,并且1/(ai+aj)=1/ai+1/a ...
- 2017多校第5场 HDU 6085 Rikka with Candies bitset
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6085 题意:存在两个长度为n,m的数组A,B.有q个询问,每个询问有一个数字k,可以得到Ai%Bj=k ...
- 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 ...
随机推荐
- 【LOJ】#3031. 「JOISC 2019 Day1」聚会
LOJ#3031. 「JOISC 2019 Day1」聚会 听说随机可过? 我想了很久想了一个不会被卡的做法,建出前\(u - 1\)个点的虚树,然后找第\(u\)个点的插入位置,就是每次找一条最长链 ...
- DLL导出函数
使用DEF文件从DLL导出 模块定义(.def)文件时包含一个或多个描述DLL各种属性的Module语句的文本文件.如果不使用_declspec(dllexport)关键字导出DLL的函数,则DLL需 ...
- MyBatis学习存档(1)——入门
一.简介 MyBatis的前身是iBatis,本是Apache的一个开源的项目 MyBatis是一个数据持久层(ORM)框架,把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现 MyB ...
- Web开发Flask框架学习笔记
Python 是一种跨平台的[计算机程序设计语言],是一种面向对象的动态类型语言,Python是纯粹的自由软件,源代码和解释器CPython遵循 GPL(GNU General Public Lice ...
- Hello World!!!
C #include <stdio.h> int main() #main 入口函数 { printf("Hello,World!"); #printf 函数打印 ; ...
- C#面向对象21 接口
接口的规范: 1.接口是一种规范.只要一个类继承了一个接口,这个类就必须实现这个接口中所有的成员. 2.为了多态,接口不能被实例化,接口不new(不能创建对象) 3.接口中的成员不能加“访问修饰符”, ...
- MVC4学习要点记四
一.使用原生SQL使用EF的一个优点就是自动帮我们生成SQL,这在常规情况下很方便,但有些情况下用EF却不适合.另外还有些特别复杂的语句,利用EF很难生成.所以,EF提供一组方法用来执行原生的SQL. ...
- 【html】 iframe 和 frameset 的区别
一.两者的相同点和不同点 相同点: iframe 和frameset都是html布局的框架布局 不同点: iframe是一个内联框架,是在页面里生成内部框架 frameset定义一个框架集,包含多个子 ...
- vue编程式导航,命名路由
//使用 window.location.href 的形式,叫做 编程式导航 绑定事件的形式 <template> <div class="goods-item" ...
- netty的断线重连问题
手里的这个项目需要作为客户端,不断的接收服务端发来的数据,用的netty框架,但是一直存在一个问题,就是断线重连问题. 什么是断线重连呢? 就是我们这个客户端要保证一直与服务端保持连接,这样客户端才能 ...