ABC389

C

link

手写队列存下开始位置和长度,模拟即可。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int q;
struct nd{
	int st,len;
}a[300005];
int h = 1,t;
int shao;

signed main(){
	
	cin >> q;
	while(q--){
		int tp,x;
		cin >> tp;
		if(tp == 1){
			cin >> x;
			t++;
			a[t] = {a[t-1].st+a[t-1].len,x};
		}
		else if(tp == 2){
			shao += a[h].len;
			h++;
		}
		else if(tp == 3){
			cin >> x;
			cout << a[h+x-1].st-shao << endl;
		}
	}
	
	return 0;
	
}

D

link


没写原点和x轴y轴,扣分!
这是一个半径为3的圆。
先看这个图,我们可以发现一个圆被两条坐标轴分成了四份,显然,四份都是一样的。
那么我们先计算坐标轴上的正方形。我们可以看做原点把两条坐标轴分为了四段,那么一段上就有R1个正方形,那么四段再加上原点就是4(R1)+1
那么既然四半都一样,那我们就只考虑第一象限的那一半。
考虑一个正方形(i,j),如果它在圆内,当且仅当(i+0.5,j+0.5)这个点在圆里,也就是说(i+0.5)2+(j+0.5)2R,即(i+0.5)2+(j+0.5)2R2,两边同乘以4,就是(2i+1)2+(2j+1)24R2,那么我们枚举i,二分查找对应的最大的j,那么当x=i时,y=1j都可以满足条件(在圆内),就都可以加到答案里(答案加上j),都做完再变成四倍即可。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int R;
int ans;

int suan(int i,int j){
	return (2*i+1)*(2*i+1)+(2*j+1)*(2*j+1);
}

int finj(int x){
	int l = 0,r = R;
	while(l < r){
		int mid = (l+r+1)/2;
		if(suan(x,mid) <= 4*R*R) l = mid;
		else r = mid-1;
	}
	return l;
}

signed main(){
	
	cin >> R;
	
	for(int i = 1;i < R;++ i){
		int j = finj(i);
		ans += j;
	}
	ans *= 4;
	ans += 4*(R-1)+1;
	cout << ans;
	
	return 0;
	
}

E

link

首先我们考虑一个事情:我们买一个i东西是pi元,买两个是4pi元,相当于第二个用了3pi元。
那么我们可以把每个物品拆开,拆成很多个,然后从小到大一个一个选。

点击查看代码
#include<bits/stdc++.h>

#define int unsigned long long

using namespace std;

int n,m;
int p[200005];

bool check(int x){
	int ans = 0;
	for(int i = 1;i <= n;++ i){
		int w = (x/p[i]+1)/2;
		if(w == 0) continue;
		int ww = w;
		if(ww > m) return false;
		if(ww > m/w) return false;
		ww *= w;
		if(ww > m/p[i]) return false;
		ww *= p[i];
		if(ans > m-ww) return false;
		ans += ww;
	}
	return true;
}

signed main(){
	
	cin >> n >> m;
	for(int i = 1;i <= n;++ i)
		cin >> p[i];
	
	int l = 0,r = m,mid;
	while(l < r){
		mid = (l+r+1)/2;
		if(check(mid)) l = mid;
		else r = mid-1;
	}
	
	int ans = 0,sum = 0;
	for(int i = 1;i <= n;++ i){
		int w = (l/p[i]+1)/2;
		ans += w;
		sum += w*w*p[i];
	}
	cout << ans+(m-sum)/(l+1);
	
	return 0;
	
}

F

link

首先我们考虑一个事情:初始是x的最终结果一定不会比初始是x+1的大,因为如果大的话,一定会在某个位置相等,如果相等了,后面就都一样了,一定会小于等于。这个现在用不到,待会会用。
我们考虑fi,j表示已经进行到了第i局,初始分数是j最终分数。
我们可以很容易的写出转移方程:fi,j=fi1,j(fi1,j不属于LiRi之间),fi,j=fi1,j+1(fi1,j属于LiRi之间)。
那么我们现在只需要找到fi1,j属于LiRi之间那些位置,由于我们推出来的第一条性质,我们可以知道,fi是单调不降的,那么数值在LiRi之间一定是一个区间,那么我们就可以二分查找这个区间,再用树状数组把这个区间加一即可。
这里我们的dp数组是一个二维的,但是由于可以直接在原来的基础上加1,所以我们用一维即可。

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int m = 5e5;

int lb(int x){return x&(-x);}

int n;
int l[200005],r[200005];
int ans[500005];

void add(int d,int x){
	for(int i = d;i <= m;i += lb(i))
		ans[i] += x;
}

int sum(int x){
	int res = 0;
	for(int i = x;i >= 1;i -= lb(i))
		res += ans[i];
	return res;
}

int findl(int x){
	int l = 1,r = m,mid;
	while(l < r){
		mid = (l+r)/2;
		if(sum(mid) >= x) r = mid;
		else l = mid+1;
	}
	return r;
}

int findr(int x){
	int l = 1,r = m,mid;
	while(l < r){
		mid = (l+r+1)/2;
		if(sum(mid) <= x) l = mid;
		else r = mid-1;
	}
	return l;
}

void init(){
	for(int i = 1;i <= m;++ i) add(i,1);
}

signed main(){
	
	init();
	
	cin >> n;
	for(int i = 1;i <= n;++ i){
		cin >> l[i] >> r[i];
		int wl = findl(l[i]);
		int wr = findr(r[i]);
		add(wl,1);
		add(wr+1,-1);
	}
	
	int q;
	cin >> q;
	while(q--){
		int x;
		cin >> x;
		cout << sum(x) << endl;
	}
	
	return 0;
	
}
posted @   不认命,就是哪吒的命!  阅读(5)  评论(0编辑  收藏  举报
相关博文:
· ABC354
· ABC369
· ABC389
· ABC 359
· ABC393
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示