NC23054 华华开始学信息学
Posted 空白菌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NC23054 华华开始学信息学相关的知识,希望对你有一定的参考价值。
题目
题目描述
因为上次在月月面前丢人了,所以华华决定开始学信息学。十分钟后,他就开始学树状数组了。这是一道树状数组的入门题:
给定一个长度为 \\(N\\) 的序列 \\(A\\) ,所有元素初值为 \\(0\\) 。接下来有 \\(M\\) 次操作或询问:
操作:输入格式:1 D K,将 \\(A_D\\) 加上 \\(K\\) 。
询问:输入格式:2 L R,询问区间和,即 \\(\\sum_i=L^RA_i\\) 。
华华很快就学会了树状数组并通过了这道题。月月也很喜欢树状数组,于是给华华出了一道进阶题:
给定一个长度为 \\(N\\) 的序列 \\(A\\) ,所有元素初值为 \\(0\\) 。接下来有 \\(M\\) 次操作或询问:
操作:输入格式:1 D K,对于所有满足 \\(1\\le i\\le N\\) 且 $i\\equiv0 \\pmod D $ 的 \\(i\\) ,将 \\(A_i\\) 加上 \\(K\\) 。
询问:输入格式:2 L R,询问区间和,即 \\(\\sum_i=L^RA_i\\) 。
华华是个newbie,怎么可能会这样的题?不过你应该会吧。
输入描述
第一行两个正整数 \\(N\\) 、\\(M\\) 表示序列的长度和操作询问的总次数。
接下来M行每行三个正整数,表示一个操作或询问。
输出描述
对于每个询问,输出一个非负整数表示答案。
示例1
输入
10 6
1 1 1
2 4 6
1 3 2
2 5 7
1 6 10
2 1 10
输出
3
5
26
备注
\\(1\\le N,M\\le10^5\\) , \\(1\\le D\\le N\\) , \\(1\\le L\\le R\\le N\\) , \\(1\\le K \\le 10^8\\)
题解
知识点:树状数组,根号分治。
显然,这道题的修改并不能转化为可懒标记的区间修改,也没有很好的方法转化为单点修改。
我们可以考虑暴力优化的一种,根号分治。将修改操作的 \\(D\\) 分为两部分,按阈值 \\(B\\) 划分:
- \\(D \\leq B\\) 时,采用标记法, 用 \\(add\\) 数组表示某个 \\(D\\) 加了多少,复杂度 \\(O(1)\\) 。
- \\(D > B\\) 时,采用暴力修改法,倍增修改树状数组 \\(x \\equiv 0 \\pmod D\\) 的点,复杂度 \\(O\\left( \\dfracnB \\log n \\right)\\) 。
修改总体复杂度为 \\(O\\left( \\dfracnB \\log n \\right)\\) 。
同时,查询操作也要随之改变:
- \\(D \\leq B\\) 部分,暴力累和每个 \\(D\\) 的贡献,即 \\(\\displaystyle \\sum_i=1^B add_i \\cdot \\left( \\left \\lfloor \\fracri \\right \\rfloor - \\left \\lfloor \\fracl-1i \\right \\rfloor \\right)\\) ,复杂度 \\(O(B)\\)。
- \\(D>B\\) 部分,直接查询树状数组即可,复杂度 \\(O(\\log n)\\) 。
查询总体复杂度为 \\(O(B + \\log n)\\) 。
我们尝试平衡查询和修改的复杂度。假设 \\(B\\) 能使 \\(\\log n\\) 被忽略,则需要满足 $ \\dfracnB \\log n = B$ ,解得 \\(B = \\sqrtn \\log n\\) 。因此, \\(B = \\sqrtn \\log n\\) 是我们所需要的阈值,其能使总体复杂度为 \\(O(\\sqrtn \\log n)\\) 。
实际上,这道题用理论最优阈值时间不是最优的,用 \\(B = \\sqrt n\\) 快将近一倍,可能由于数据的 \\(D\\) 普遍较小,使得查询代价上升较明显。
这里采用 \\(B = \\sqrt n\\) 阈值。
时间复杂度 \\(O(m\\sqrtn \\log n)\\)
空间复杂度 \\(O(n)\\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T>
class Fenwick
int n;
vector<T> node;
public:
Fenwick(int _n = 0) init(_n);
void init(int _n)
n = _n;
node.assign(n + 1, T::e());
void update(int x, T val) for (int i = x;i <= n;i += i & -i) node[i] += val;
T query(int x)
T ans = T::e();
for (int i = x;i >= 1;i -= i & -i) ans += node[i];
return ans;
T query(int l, int r) return query(r) - query(l - 1);
;
struct T
ll sum;
static T e() return 0 ;
T &operator+=(const T &x) return sum += x.sum, *this;
friend T operator-(const T &a, const T &b) return a.sum - b.sum ;
;
ll add[100007];
int main()
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
Fenwick<T> fw(n);
for (int i = 1;i <= m;i++)
int op;
cin >> op;
if (op == 1)
int d, k;
cin >> d >> k;
if (d * d <= n) add[d] += k;
else for (int i = d;i <= n;i += d) fw.update(i, k );
else
int l, r;
cin >> l >> r;
ll ans = fw.query(l, r).sum;
for (int i = 1;i * i <= n;i++) ans += add[i] * (r / i - (l - 1) / i);
cout << ans << \'\\n\';
return 0;
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17367268.html
华华给月月出题
题目链接:
注意到x^n是个积性函数就能做了,然后就是一波线性筛素数+快速幂的操作
#include <bits/stdc++.h> using namespace std; #define re register #define ll long long const int mod=1e9+7; const int maxn=1.3*10000000; void read(int &a) { a=0; int d=1; char ch; while(ch=getchar(),ch>‘9‘||ch<‘0‘) if(ch==‘-‘) d=-1; a=ch-‘0‘; while(ch=getchar(),ch>=‘0‘&&ch<=‘9‘) a=a*10+ch-‘0‘; a*=d; } void write(int x) { if(x<0) putchar(45),x=-x; if(x>9) write(x/10); putchar(x%10+‘0‘); } int vis[maxn],p[maxn]; int quickmod(int x,int y) { int result=1; int base=x; while(y) { if(y&1) result=1ll*result*base%mod; base=1ll*base*base%mod; y>>=1; } return result; } int main() { int n; read(n); int ans=1,cnt=1; for(re int i=2;i<=n;i++) { if(!vis[i]) p[cnt++]=i,vis[i]=quickmod(i,n); for(re int j=1;j<=cnt&&p[j]*i<=n;j++) { vis[i*p[j]]=1ll*vis[i]*vis[p[j]]%mod; if(i%p[j]==0) break; } ans^=vis[i]; } write(ans); return 0; }
以上是关于NC23054 华华开始学信息学的主要内容,如果未能解决你的问题,请参考以下文章