博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3434 WC2014时空穿梭(莫比乌斯反演)
阅读量:5344 次
发布时间:2019-06-15

本文共 2362 字,大约阅读时间需要 7 分钟。

  考虑枚举相邻点距离差的比例。显然应使比例值gcd为1以保证不重复统计。确定比例之后,各维坐标的方案数就可以分开考虑。设比例之和为k,则若坐标上限为m,该维坐标取值方案数即为Σm-ki (i=1~⌊m/k⌋),也即⌊m/k⌋·m-k·(⌊m/k⌋+1)·⌊m/k⌋/2,设其为f(m,k)。总方案数即将各维方案数相乘,设为F(k)。

  于是得到答案即为ΣkΣa1Σa2……Σac-2 [gcd(a1,a2,……,ac-2,k)=1]·F(k)。套路一波,得到Σk F(k)·(Σd μ(d)·g(k/d)) (d|k),其中g(n)为将n划成c-1份的方案数,也即C(n-1,c-2)。对每个询问暴力一遍,复杂度即为O(Tnm)。注意这里的组合数只能递推,因为值域比模数还大。

  卡卡常就过了毕竟正解的复杂度也优不到哪里去。

  考虑优化。容易想到整除分块。固定⌊m/k⌋后,要求和的部分是一个关于k的n次多项式。分治NTT暴力求出多项式系数对各项求个前缀和即可。

#include
#include
#include
#include
#include
#include
using namespace std;#define ll long long#define N 100010#define P 10007char getc(){ char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}int gcd(int n,int m){ return m==0?n:gcd(m,n%m);}int read(){ int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') { if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f;}int T,n,c,a[30],b[30],mobius[N],prime[N],g[30][N],f[15][30][N],p[30],C[N][30],fac[N],inv[N],cnt;bool flag[N];int main(){#ifndef ONLINE_JUDGE freopen("bzoj3434.in","r",stdin); freopen("bzoj3434.out","w",stdout); const char LL[]="%I64d\n";#else const char LL[]="%lld\n";#endif mobius[1]=1; for (int i=2;i<=N-10;i++) { if (!flag[i]) prime[++cnt]=i,mobius[i]=-1; for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++) { flag[prime[j]*i]=1; if (i%prime[j]==0) break; mobius[prime[j]*i]=-mobius[i]; } } C[0][0]=1; for (int i=1;i<=N-10;i++) for (int j=0;j<=min(20,i);j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P; for (int c=2;c<=20;c++) for (int i=1;i<=N-10;i++) if (mobius[i]) for (int j=i;j<=N-10;j+=i) g[c][j]=(g[c][j]+mobius[i]*(c-2>j/i-1?0:C[j/i-1][c-2])+P)%P; int s=1; for (int c=2;c<=20;c++) for (int i=1;i<=N-10;i++) { int s=1; for (int k=0;k<=11;k++) { f[k][c][i]=(f[k][c][i-1]+g[c][i]*s)%P; s=s*i%P; } } T=read(); while (T--) { n=read(),c=read();int m=N,ans=0; for (int i=1;i<=n;i++) m=min(m,a[i]=read()); for (int i=1;i<=m;i++) { int t=m;p[0]=1;for (int j=1;j<=n;j++) t=min(t,a[j]/(b[j]=a[j]/i)),p[j]=0; for (int j=1;j<=n;j++) { for (int k=j;k>=1;k--) p[k]=(1ll*p[k]*b[j]*a[j]-1ll*p[k-1]*(b[j]+1)*b[j]/2)%P; p[0]=1ll*p[0]*b[j]*a[j]%P; } for (int j=0;j<=n;j++) ans=(ans+p[j]*(f[j][c][t]-f[j][c][i-1])%P+P)%P; i=t; } cout<
<

 

转载于:https://www.cnblogs.com/Gloid/p/10187552.html

你可能感兴趣的文章
如何用ssh挂载远程目录
查看>>
常用的系统查询语句
查看>>
10651
查看>>
Leetcode: Convert Sorted List to Binary Search Tree
查看>>
ionic3-ng4学习见闻--(aot方式打包问题解决方案)
查看>>
Android系统Recovery工作原理之使用update.zip升级过程分析(三)
查看>>
使用GridFsTemplate在Mongo中存取文件
查看>>
使用sqoop从mysql导入数据到hive
查看>>
SAP GUI里Screen Painter的工作原理
查看>>
什么?在SAP中国研究院里还需要会PHP开发?
查看>>
老年玩家每日水题(完结)
查看>>
机器学习——前馈神经网络
查看>>
Android之ViewPager 第一课
查看>>
github协同开发
查看>>
Android 弹出对话框使底部背景变暗
查看>>
QT5:介绍
查看>>
编程语言
查看>>
swagger常用注解说明
查看>>
腾讯面试-开发测试职位
查看>>
关于船票售票外网系统的安全架构的的设想。
查看>>