BZOJ1547: 周末晚会

https://lydsy.com/JudgeOnline/problem.php?id=1547

分析:

  • 对于一个串旋转若干次会回到本身,旋转次数即是同构个数,这个东西和最小整除周期有关。
  • 设\(f_i\)表示有多少个串的最小整除周期是\(i\),\(g_i=\sum\limits_{j|i}f_j,f_i=\sum\limits_{j|i}g_j\mu(i/j)\)。
  • 那么答案就是\(\sum\limits_{i|n}\frac{f_i}{i}\)。
  • 当\(n\le K\)时,\(g_i=2^i\), 否则,考虑求一个\(h_i\)表示长度为\(i\)重复出现次数小于等于\(K\)的个数(内部),求\(h\)前缀和优化一下\(O(n)\)求, 那么枚举最长前缀1+最长后缀1的个数\(j\),可得\(g_i=\sum\limits_{j=0}^{K}(j+1)\times h_{i-j-2}\),这个也可以前缀和优化一下\(O(1)\)求。
  • 考虑到有用的\(f,g\)一共约数个数个,时间复杂度为\(O(n+\sigma(n)^2)\)。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define mod 100000007
#define N 2050
#define M 2050
typedef long long ll;
int n,K;
ll f[N],g[N];
int pri[M],cnt,mu[M];
bool vis[M];
int w[N],tot,mi[M],h[M],sum[M],sum2[M];
void ins(int x) {
w[++tot]=x;
}
ll qp(ll x,ll y) {
ll re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re;
}
void sieve() {
int i,j;
mu[1]=1;
for(i=2;i<=n;i++) {
if(!vis[i]) {
pri[++cnt]=i; mu[i]=-1;
}
for(j=1;j<=cnt&&i*pri[j]<=n;j++) {
vis[i*pri[j]]=1;
if(i%pri[j]==0) {
mu[i*pri[j]]=0; break;
}
mu[i*pri[j]]=-mu[i];
}
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&K);
cnt=0;
if(n<=K) {
memset(f,0,sizeof(f));
int i,j;
sieve();
for(mi[0]=i=1;i<=n;i++) mi[i]=mi[i-1]*2%mod;
for(i=1;i<=n;i++) for(j=i;j<=n;j+=i) {
f[j]=(f[j]+mi[i]*mu[j/i])%mod;
}
int ans=0;
for(i=1;i<=n;i++) if(n%i==0) ans=(ans+f[i]*qp(i,mod-2))%mod;
printf("%d\n",(ans%mod+mod)%mod);
continue;
}else {
memset(h,0,sizeof(h));
memset(f,0,sizeof(f));
memset(h,0,sizeof(h));
tot=0;
int i,j;
for(i=1;i*i<=n;i++) {
if(n%i==0) {
ins(i); if(n/i!=i) ins(n/i);
}
}
sieve();
for(mi[0]=i=1;i<=n;i++) mi[i]=mi[i-1]*2%mod;
h[0]=1; sum[0]=1;
for(i=1;i<=K;i++) h[i]=mi[i],sum[i]=(sum[i-1]+h[i])%mod;
for(i=K+1;i<=n;i++) {
if(i>K+1) h[i]=(sum[i-1]-sum[i-K-2]+mod)%mod;
else h[i]=sum[i-1];
sum[i]=(sum[i-1]+h[i])%mod;
}
for(i=0;i<=n;i++) sum2[i]=(sum2[i-1]+ll(n-i)*h[i])%mod;
for(i=1;i<=tot;i++) {
if(w[i]<=K+1) g[i]=mi[w[i]]-1;
else {
/*for(j=0;j<=K;j++) {
g[i]=(g[i]+ll(j+1)*h[w[i]-j-2])%mod;
}*/
ll ss2,ss1;
if(w[i]>K+2) ss2=sum2[w[i]-2]-sum2[w[i]-K-3],ss1=sum[w[i]-2]-sum[w[i]-K-3];
else ss2=sum2[w[i]-2],ss1=sum[w[i]-2];
g[i]=((ss2-ll(n-w[i]+1)*ss1)%mod+mod)%mod;
//g[i]=((sum2[w[i]-2]-sum2[w[i]-K-2]-ll(n-w[i]+1)*(sum[w[i]-2]-sum[w[i]-K-2]))%mod+mod)%mod;
}
}
for(i=1;i<=tot;i++) {
for(j=1;j<=tot;j++) if(w[j]%w[i]==0) {
f[j]=(f[j]+g[i]*mu[w[j]/w[i]])%mod;
}
}
int ans=0;
for(i=1;i<=tot;i++) ans=(ans+ll(f[i])*qp(w[i],mod-2))%mod;
printf("%d\n",(ans%mod+mod)%mod);
continue;
}
}
}

最新文章

  1. Bootstrap3系列:按钮式下拉菜单
  2. CentOS 7 配置静态 ip
  3. LR录制Flex+Web,登录功能之登录密码出错的处理
  4. js禁止用户右键等操作
  5. GDC2016 [全境封锁],11个种类5个派系的敌人设计思路
  6. Cable master(二分题 注意精度)
  7. Unity3d 基础知识学习 工具篇
  8. pyqt下拉菜单和打开指定的内容(或者exe,doc,ppt,url等内容)
  9. MySql命令——命令行客户机的分隔符
  10. 解决Gradle minifyEnabled无法找到错误
  11. 转:JAVA常见错误处理方法 和 JVM内存结构
  12. 备忘录之 —— .bashrc(IC工具篇)
  13. 用C语言做一个横板过关类型的控制台游戏
  14. 查找数组中重复的唯一元素+时间复杂度O(n)+空间复杂度O(1)
  15. js中setInterval和setTimeout区别和用法
  16. Android ecludeFromRecents
  17. delphi 动态绑定代码都某个控件
  18. Python中新式类 经典类的区别(即类是否继承object)
  19. CPP_const&amp;static
  20. Algorithmic Trading[z]

热门文章

  1. Python3.x:pdf2htmlEX(解析pdf)安装和使用
  2. CreateWindow创建无边框 可拉伸窗体
  3. spring security结合数据库验证用户-XML配置方式
  4. 织梦DedeCMS实现 三级栏目_二级栏目_一级栏目_网站名称 的效果代码
  5. MySQL explain 、explain extended用法
  6. Sqoop-将Hive ORC表导出到MySQL
  7. Java中List集合的常用方法
  8. CocoaPods学习系列5——错误集锦
  9. 开发中Dialog多弹窗管理
  10. H5滑动穿透(TODO)