题目大意

  有一个长度为 \(n\) 的序列。

  有 \(m\) 次修改,每次给你 \(x,y\),令 \(\forall 1\leq i\leq \lfloor\frac{n}{x}\rfloor,a_{ix}=a_{ix}+iy\)

  还有 \(q\) 次询问,每次给你 \(x\),求 \(\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}ia_{ix}\)

  对 \(998244353\) 取模。

  \(n\leq {10}^9,m,q\leq 200000\),记 \(z\) 为所有 \(x\) 的 \(\operatorname{lcm}\),那么 \(z\) 的质因子个数 \(w\) 不超过 \(10\)

题解

  首先你要会 \(O(n\log\log n)\) 求高维前缀和&后缀和,这样就可以拿到 \(65\) 分。

  容易发现,所有 \(z\) 的不超过 \(n\) 的因子个数 \(s\leq 200000\)。

  因为所有修改&询问的数都是 \(z\) 的因子,所以可以把那些不是 \(z\) 的因子的位置的贡献放在那个数和 \(z\) 的 \(\gcd\) 处统计。

  具体来说,我们在求高维前缀和的时候只求 \(z\) 的不超过 \(n\) 的因子的答案,求完之后把每个位置 \(x\) 的值乘上一个系数 \(f(\frac{n}{x})\) 。

\[f(n)=\sum_{i=1}^ni^2[\gcd(i,z)=1]
\]

  \(f\) 可以筛出来。

  高维后缀和也可以用类似的方法做。

  然后就能得到答案了。

  时间复杂度:\(O(w(s+\sqrt{n}))\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<functional>
#include<cmath>
#include<tr1/unordered_map>
//using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
const ll inv6=fp(6,p-2);
std::tr1::unordered_map<int,int> s;
//int s[10000010];
int c[100010];
int cnt;
int a[200010];
int tot;
int ax[200010],ay[200010],bx[200010];
int n,m,q;
void dfs(int x,int y,int b)
{
if(b)
a[++tot]=x;
if((ll)x*c[y]<=n)
dfs(x*c[y],y,1);
if(y<cnt)
dfs(x,y+1,0);
}
ll f1[100010],f2[100010];
ll sum(ll x)
{
return x*(x+1)%p*(2*x+1)%p*inv6%p;
}
void sieve()
{
int m=100000;
int mx=n/(m+1);
for(int i=1;i<=m;i++)
f1[i]=sum(i);
for(int i=1;i<=mx;i++)
f2[i]=sum(n/i);
for(int i=1;i<=cnt;i++)
{
ll x=(ll)c[i]*c[i]%p;
int n1=mx/c[i];
for(int j=1;j<=n1;j++)
f2[j]=(f2[j]-x*f2[j*c[i]])%p;
for(int j=n1+1;j<=mx;j++)
f2[j]=(f2[j]-x*f1[n/((ll)j*c[i])])%p;
for(int j=m;j>=1;j--)
f1[j]=(f1[j]-x*f1[j/c[i]])%p;
}
}
ll query(int x)
{
return x<=100000?f1[x]:f2[n/x];
}
int main()
{
open("loj561");
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&ax[i],&ay[i]);
s[ax[i]]=(s[ax[i]]+ay[i])%p;
int x=ax[i];
for(int j=1;j<=cnt;j++)
while(x%c[j]==0)
x/=c[j];
for(int j=2;j*j<=x;j++)
if(x%j==0)
{
c[++cnt]=j;
while(x%j==0)
x/=j;
}
if(x!=1)
c[++cnt]=x;
}
for(int i=1;i<=q;i++)
{
scanf("%d",&bx[i]);
int x=bx[i];
for(int j=1;j<=cnt;j++)
while(x%c[j]==0)
x/=c[j];
for(int j=2;j*j<=x;j++)
if(x%j==0)
{
c[++cnt]=j;
while(x%j==0)
x/=j;
}
if(x!=1)
c[++cnt]=x;
}
std::sort(c+1,c+cnt+1);
dfs(1,1,1);
std::sort(a+1,a+tot+1);
sieve();
for(int i=1;i<=cnt;i++)
for(int j=1;j<=tot;j++)
if(a[j]%c[i]==0)
s[a[j]]=(s[a[j]]+(ll)s[a[j]/c[i]]*c[i])%p;
for(int i=1;i<=tot;i++)
s[a[i]]=s[a[i]]*query(n/a[i])%p;
for(int i=1;i<=cnt;i++)
for(int j=tot;j>=1;j--)
if(a[j]%c[i]==0)
s[a[j]/c[i]]=(s[a[j]/c[i]]+(ll)s[a[j]]*c[i])%p;
for(int i=1;i<=q;i++)
printf("%lld\n",(s[bx[i]]+p)%p);
return 0;
}

【LR9】【LOJ561】CommonAnts 的调和数 数论 筛法的更多相关文章

  1. 「LibreOJ Round #9」CommonAnts 的调和数

    题解: 对于subtask3:可以把相同的归在一起就是$nlogn$的了 对于subtask4: 可以使用高维前缀和的技术,具体的就是把每个质因数看作一维空间 那么时间复杂度是$\sum \limit ...

  2. XDU 1022 (数论筛法+前缀和)

    解法一:数论筛法+前缀和 //其实题目中f[n]的值可理解为存在多少个整数对使a*b<=n #include<cstdio> #define N 1007 #define maxn ...

  3. 数论 - 筛法暴力打表 --- hdu : 12876 Quite Good Numbers

    Quite Good Numbers Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB Total submit ...

  4. ACM主要算法

    ACM主要算法ACM主要算法介绍 初期篇 一.基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构 ...

  5. ACM常用算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  6. ACM需要掌握算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  7. ACM用到的算法。先做个笔记,记一下

    ACM 所有算法 数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 ...

  8. ACM算法目录

    数据结构 栈,队列,链表 •哈希表,哈希数组 •堆,优先队列 双端队列 可并堆 左偏堆 •二叉查找树 Treap 伸展树 •并查集 集合计数问题 二分图的识别 •平衡二叉树 •二叉排序树 •线段树 一 ...

  9. ACM技能表

    看看就好了(滑稽) 数据结构 栈 栈 单调栈 队列 一般队列 优先队列/单调队列 循环队列 双端队列 链表 一般链表 循环链表 双向链表 块状链表 十字链表 邻接表/邻接矩阵 邻接表 邻接多重表 Ha ...

随机推荐

  1. PHP技能树

  2. 浅谈Semaphore类

    Semaphore类有两个重要方法 1.semaphore.acquire(); 请求一个信号量,这时候信号量个数-1,当减少到0的时候,下一次acquire不会再执行,只有当执行一个release( ...

  3. git rebase 使用详解

    rebase 假设你现在基于远程分支"origin",创建一个叫"mywork"的分支. $ git checkout -b mywork origin   现 ...

  4. c/c++ 网络编程 UDP 主机网络信息取得

    网络编程 UDP 主机网络信息取得 1,if_nametoindex 通过网卡名字取得网卡编号 2,if_indextoname 通过网卡编号取得网卡名字 #include <stdio.h&g ...

  5. Asp.Net Core 实现服务的批量注册注入

  6. SQLServer之创建主XML索引

    创建主XML索引注意事项 若要创建主 XML 索引,请使用 CREATE INDEX (Transact-SQL) Transact-SQL DDL 语句. XML 索引不完全支持可用于非 XML 索 ...

  7. 我的第一个python web开发框架(27)——定制ORM(三)

    在上一章中,我们已经创建好ORM的基类了,接下来要做的就是将基类的常用方法一一实现. 首先我们来看看之前项目中,最常见的获取指定主键的记录实体 @get('/api/product/<id:in ...

  8. 调用远程主机上的 RMI 服务时抛出 java.rmi.ConnectException: Connection refused to host: 127.0.0.1 异常原因及解决方案

    最近使用 jmx 遇到一个问题,client/server 同在一台机器上,jmx client能够成功连接 server,如果把 server 移植到另一台机器上192.168.134.128,抛出 ...

  9. HBase源码实战:ImportTsv

    /** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agr ...

  10. 【转】VUE 爬坑之旅-- 如何对公共JS,CSS进行统一管理,全局调用

    原文:https://blog.csdn.net/zgh0711/article/details/78664262 vue 中,将页面分为了各个组件,我们写好组件,就可以将这个组件运用到其他各个页面中 ...