【 Educational Codeforces Round 71 (Rated for Div. 2) F】Remainder Problem【分块】

题意:

一个长度为 5 1 0 5 5*10^5 的数组,初始为空,支持两种操作。操作 1 1 1   x   y 1\ x\ y 表示将 a x a_x 增加 y y 。操作 2 2 2   x   y 2\ x\ y ,表示统计所有下标模 x x y y 的数的和,一共有 5 1 0 5 5*10^5 次操作。 ( 1 x 500000 ) (1\leq x\leq 500000)


思路:

昨晚最后有半个小时写这题,但是还是没有啥思路,完全没有往分块上去想…分块技能树有点缺乏啊!最后 10   m i n 10\ min ,感觉搞不定了,乱打一发线段树成功 T L E TLE …自闭了…

所以正解就是分块,当然分块的复杂度为 n n n*\sqrt n 。我们来考虑下此题如何进行分块,显然要对于模数进行分类。 5 1 0 5 = 710 \sqrt {5*10^5}=710 ,我们对于模数大于 710 710 的数,直接暴力求,复杂度为 O ( n ) O(\sqrt n) 。对于模数小于 710 710 的数,我们预先统计答案直接求得。

那么对于模数小于 710 710 的数,如何预先处理答案呢?对于 a x = a x + y a_x=a_x+y ,我们暴力所有模数, b [ i ] [ j ] b[i][j] 表示模 i i j j 的数的 s u m sum 和。因此我们令 b [ i ] [ x % i ] = b [ i ] [ x % i ] + y b[i][x\%i]=b[i][x\%i]+y ,这样的复杂度也是 O ( n ) O(\sqrt n) ,因此最终复杂度为 O ( n n ) O(n*\sqrt n) ,分块成功。


总结:

反思一下为什么没有想到分块,如果想到了分块,按理来说思路也没有那么难想。

这么看来的话,应该是思维体系里完全没有分块这个意识,数据结构的技能树里分块这里非常灰暗…看来还是非常有必要抽出一段时间来巩固所有的基础专题。继续加油!


代码:

#include <bits/stdc++.h>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 5*1e5+100;
const db EPS = 1e-9;
using namespace std;

ll a[N],b[715][715];

int main()
{
	int _; scanf("%d",&_);
	while(_--){
		int op; scanf("%d",&op);
		if(op == 1){
			int x,y; scanf("%d%d",&x,&y);
			a[x] += y;
			rep(i,1,710) b[i][x%i] += (ll)y;
		}
		else{	
			int x,y; scanf("%d%d",&x,&y);
			if(x <= 710) printf("%lld\n",b[x][y]);
			else{
				ll tp = 0;
				for(int i = y; i <= (int)5*1e5; i += x) tp += a[i];
				printf("%lld\n",tp);
			}
		}
	}
	return 0;
}
发布了244 篇原创文章 · 获赞 115 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/100031900