【HDU 6274】Master of sequence【二分答案+下取整转换】

题意:

给定长度为 n n 的序列 a a 与序列 b b m m 次操作,操作一共有三种类型。
· 1   x   y 1 \ x \ y :令 a x = y a_x=y
· 2   x   y 2\ x\ y :令 b x = y b_x=y
· 3   k 3\ k :询问 m i n min { t k S ( t ) t|k\leq S(t) }, S ( t ) = i = 1 n t b i a i S(t)=\sum\limits_{i=1}^{n}\lfloor\frac{t-b_i}{a_i} \rfloor
( 1 n 1 0 5 , 1 m 1 0 4 , 1 a i 1000 , 1 b i , k 1 0 9 ) (1\leq n \leq 10^5,1\leq m \leq 10^4,1\leq a_i\leq 1000,1\leq b_i,k\leq 10^9)
在这里插入图片描述


思路:

看完题就可以发现,整道题最关键的地方就是如何处理下取整,而处理下取整问题通常都是转换成余数形式来进行求解, x y = k y + c y , c = x   m o d   y \lfloor \frac{x}{y}\rfloor=\lfloor \frac{k*y+c}{y}\rfloor,c=x\ mod\ y

因此本题也可以进行简化,令 t = k 1 a i + c 1 , b i = k 2 a i + c 2 t=k_1*a_i+c_1,b_i=k_2*a_i+c_2 ,因此 t b i a i = k 1 k 2 + c 1 c 2 a i \lfloor\frac{t-b_i}{a_i} \rfloor= k_1-k_2+\lfloor\frac{c_1-c_2}{a_i} \rfloor ,因此若 c 1 < c 2 c_1< c_2 ,则 c 1 c 2 a i = 1 \lfloor\frac{c_1-c_2}{a_i} \rfloor=-1 ,否则为 0 0

由于 a a 的范围只有 1000 1000 ,因此我们可以对于每一个 a i ai ,求出 k 2 k_2 的累加值,并且维护一个数组 c n t cnt c n t [ x ] [ y ] cnt[x][y] 表示 a i = x , b i a_i=x, b_i mod a i y a_i \leq y 的个数。然后二分 t t ,每次暴力计算前 1000 1000 a i a_i 的贡献,即可完成此题。

每次更新 a b a、b 时,暴力维护 c n t cnt 数组即可。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#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 = 1e5+100;
const int M = 1000+10;
const db EPS = 1e-9;
using namespace std;

int n,a[N],m;
ll b[N],cnt[M][M],num[M],ctt[M];
//cnt[x][y]: 表示ai = x, bi%ai <= y 有多少个
//ctt[x]: 表示ai = x, bi/ai的累加
int main()
{
	int _; scanf("%d",&_);
	while(_--)
	{
		memset(cnt,0,sizeof cnt);
		memset(num,0,sizeof num);
		memset(ctt,0,sizeof ctt);
		scanf("%d%d",&n,&m);
		rep(i,1,n){
			scanf("%d",&a[i]);
			num[a[i]]++;
		} 
		rep(i,1,n){
			scanf("%lld",&b[i]);
			ctt[a[i]] += b[i]/a[i];
			rep(j,b[i]%a[i],a[i]-1) cnt[a[i]][j]++;
		} 
		rep(i,1,m){
			int op,x; ll k,y;
			scanf("%d",&op);
			if(op == 1){
				scanf("%d%lld",&x,&y);
				ctt[a[x]] -= b[x]/a[x];
				ctt[y] += b[x]/y;
				num[a[x]]--, num[y]++;
				rep(j,b[x]%a[x],a[x]-1) cnt[a[x]][j]--;
				a[x] = y;
				rep(j,b[x]%a[x],a[x]-1) cnt[a[x]][j]++;
			}
			else if(op == 2){
				scanf("%d%lld",&x,&y);
				ctt[a[x]] -= b[x]/a[x];
				ctt[a[x]] += y/a[x];
				rep(j,b[x]%a[x],a[x]-1) cnt[a[x]][j]--;
				b[x] = y;
				rep(j,b[x]%a[x],a[x]-1) cnt[a[x]][j]++;
			}
			else{
				scanf("%lld",&k);
				ll l = 1, r = 1e12, ans;
				while(l <= r){
					ll mid = (l+r)>>1;
					ll tp = 0;
					rep(i,0,1000)
						if(num[i]){
							tp += (ll)(mid/i)*(ll)num[i]-(ll)ctt[i];
							tp -= (ll)cnt[i][i-1]-(ll)cnt[i][mid%i];
						}
					if(tp >= k) ans = mid, r = mid-1;
					else l = mid+1; 
				}
				printf("%lld\n",ans);
			}
		}
	} 	
	return 0;
}
/*
2
4 6
2 4 6 8
1 3 5 7
1 2 3
2 3 3
3 15
1 3 8
3 90
3 66
8 5
2 4 8 3 1 3 6 24
2 2 39 28 85 25 98 35
3 67
3 28
3 73
3 724
3 7775
*/

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/89053393
今日推荐