ABC366

A

link

判断一下少的那个人加上剩下的所有票是否会超过另一个人,如果超过,不确定,否则目前票多的必胜。

神奇的代码
#include<bits/stdc++.h>

using namespace std;

signed main(){
	
	int n,a,b;
	cin >> n >> a >> b;
	int s = n-a-b;
	if(a < b){
		if(a+s > b){
			cout << "No";
		}
		else cout << "Yes";
	}
	else{
		if(b+s > a){
			cout << "No";
		}
		else cout << "Yes";
	}
	
	return 0;
	
}

B

link

我并没有看下面讲解只看了描述(竖线中的)
略一看样例便可知道,是一列一列从下往上输出,对于一列,如果这个位置有字符,输出,否则,如果后面(也就是上面)还有字符,输出一个*,否则break
那么我们可以存一下每一列最靠后的字符(也就是最靠上的字符),如果超出了这个,就结束。
别忘了存一下最大长度。

神奇的代码
#include<bits/stdc++.h>

using namespace std;

int n;
string s[105];
int w[105],mx;

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i){
		cin >> s[i];
		int sn = s[i].length();
		if(sn > mx) mx = sn;
		for(int j = 0;j < s[i].length();++ j)
			w[j] = (w[j] == 0)?i:w[j];
	}
	
	for(int i = 0;i < mx;++ i){
		for(int j = n;j >= 1&&j >= w[i];-- j){
			int sn = s[j].length();
			if(sn <= i) cout << '*';
			else cout << s[j][i];
		}
		cout << endl;
	}
	
	return 0;
	
}

C

link

我觉得C<B
开一个桶,如果是一个新的,个数加一,如果减没了,个数减一。

神奇的代码
#include<bits/stdc++.h>

using namespace std;

int q;
int x,tp;
int bucket[1000005],sum;

signed main(){
	
	cin >> q;
	for(int i = 1;i <= q;++ i){
		cin >> tp;
		if(tp == 1){
			cin >> x;
			bucket[x]++;
			if(bucket[x] == 1) sum++;
		}
		else if(tp == 2){
			cin >> x;
			bucket[x]--;
			if(bucket[x] == 0) sum--;
		}
		else cout << sum << endl;
	}
	
	return 0;
	
}

D

link

三维前缀和。这里提供两种思考方式。

直接想三维前缀和

考虑类比二位前缀和的容斥原理,脑补一下,反正我没脑补出来图,奇加偶减(具体可以学习一下容斥原理),那么就有qzhi,j,k=qzhi1,j,k+qzhi,j1,k+qzhi,j,k1qzhi1,j1,kqzhi1,j,k1qzhi,j1,k1+qzhi1,j1,k1+ai,j,k,查询也是类似的(详见代码)。
这个容斥原理的适用于所有维前缀和。

神奇的代码
#include<bits/stdc++.h>

using namespace std;

int n;
int q;
int a[105][105][105];
int qzh[105][105][105];

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= n;++ j)
			for(int k = 1;k <= n;++ k){
				cin >> a[i][j][k];
				qzh[i][j][k] = qzh[i-1][j][k]+qzh[i][j-1][k];
				qzh[i][j][k] += qzh[i][j][k-1];
				qzh[i][j][k] -= qzh[i-1][j-1][k];
				qzh[i][j][k] -= qzh[i-1][j][k-1];
				qzh[i][j][k] -= qzh[i][j-1][k-1];
				qzh[i][j][k] += qzh[i-1][j-1][k-1]+a[i][j][k];
			}
	
	cin >> q;
	while(q--){
		int li,ri,lj,rj,lk,rk;
		cin >> li >> ri >> lj >> rj >> lk >> rk;
		int ans = qzh[ri][rj][rk];
		ans -= qzh[li-1][rj][rk];
		ans -= qzh[ri][lj-1][rk];
		ans -= qzh[ri][rj][lk-1];
		ans += qzh[li-1][lj-1][rk];
		ans += qzh[li-1][rj][lk-1];
		ans += qzh[ri][lj-1][lk-1];
		ans -= qzh[li-1][lj-1][lk-1];
		cout << ans << endl;
	}
	
	return 0;
	
}

考虑分层

考虑按高度分层,分n层,那么每一层都是一个二位前缀和,求完所有层后,把层按一维前缀和的思路加上,查询答案的时候也按二维前缀和的思路查,只不过每一步都是把要的那几层取出来算(详见代码)。
这个思路只是一时兴起,但是是降维作用的。

神奇的代码
#include<bits/stdc++.h>

using namespace std;

int n;
int q;
int a[105][105][105];
int qzh[105][105][105];

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i){
		for(int j = 1;j <= n;++ j){
			for(int k = 1;k <= n;++ k){
				cin >> a[i][j][k];
				qzh[i][j][k] = qzh[i-1][j][k]+qzh[i][j-1][k];
				qzh[i][j][k] -= qzh[i-1][j-1][k];
				qzh[i][j][k] += a[i][j][k];
			}
		}
	}
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= n;++ j)
			for(int k = 1;k <= n;++ k)
				qzh[i][j][k] += qzh[i][j][k-1];
	
	cin >> q;
	while(q--){
		int li,ri,lj,rj,lk,rk;
		cin >> li >> ri >> lj >> rj >> lk >> rk;
		int ans = qzh[ri][rj][rk]-qzh[ri][rj][lk-1];
		int jian = qzh[ri][lj-1][rk]-qzh[ri][lj-1][lk-1];
		ans -= jian;
		jian = qzh[li-1][rj][rk]-qzh[li-1][rj][lk-1];
		ans -= jian;
		jian = qzh[li-1][lj-1][rk]-qzh[li-1][lj-1][lk-1];
		ans += jian;
		cout << ans << endl;
	}
	
	return 0;
	
}

E

link

我们把它当做一个数学题,光考虑式子,不考虑图形。
首先i=1n(|xxi|+|yyi|)=i=1n|xxi|+i=1n|yyi|D,我们发现D106,所以枚举D是可行的,那么,我们枚举t=0~D,令i=1n|xxi|=t,那么i=1n|yyi|就要Dt,那么我们求出i=1n|xxi|=tx的个数,再求出i=1n|yyi|Dty的个数,相乘即为这个t对答案的贡献,那么问题转化为求i=1n|xxi|=tx的个数和i=1n|yyi|Dty的个数。
先把i=1n|yyi|Dty个数转换一下,可以转换成i=1n|yyi|等于某个数的个数,再求一个前缀和,就有等于0~这个数的个数,也就是小于等于这个数的个数啦。那么现在两个个数形式一样了,都是i=1n|xxi|=t的个数。
问题就转化为了求i=1n|x/yx/yi|=tx/y的个数,以x为例,我们大致算一下x的范围,是2×106~2×106,因为D106的,xi106~106的,如果超过这个范围就与xi的差无论如何也不会小于D106)了,那么我们又发现可以枚举x
枚举了x,我们就需要O(1)知道i=1n|xxi|的值,我们拆一下绝对值,想象一个数轴,有一些xi和一个x,那么假设有txix之前,那么这txi拆完绝对值就是被x减去,其他的nt个就是减去x,那么最终就是i=1t(xxi)+i=t+1n(xix),再拆一下,txi=1txi+i=t+1nxi(nt)x=(2tn)xi=1txi+i=t+1nxi对于同一个t,后面两项是相同的,只是前面在变,那么我们可以枚举每一个段(xixi+1中间的数,这里左闭右开),再枚举里面的数,他们的后两项相同,只改变前一项即可,这样存一下后两项的值,在交界处改变一个即可算出。

神奇的代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,d;
int x[200005],y[100005];
int f[1000005],g[1000005];
int ans;

void suan(int a[],int w[]){
	sort(a+1,a+1+n);
	a[0] = -2e6,a[n+1] = 2e6+1;
	int q = 0,h = 0;
	for(int i = 1;i <= n;++ i) h += a[i];
	for(int i = 0;i <= n;++ i){
		if(i) q += a[i],h -= a[i];
		for(int j = a[i];j < a[i+1];++ j){
			int x = (2*i-n)*j-q+h;
			if(x <= d) w[x]++;
		}
	}
}

signed main(){
	
	cin >> n >> d;
	for(int i = 1;i <= n;++ i) cin >> x[i] >> y[i];
	
	suan(x,f);suan(y,g);
	
	for(int i = 1;i <= d;++ i) g[i] += g[i-1];
	for(int i = 0;i <= d;++ i) ans += f[i]*g[d-i];
	cout << ans;
	
	return 0;
	
}

F

link

首先考虑顺序问题,假设就是把这n个函数排个序,使得算出来的数最大。简单推理一下。

首先考虑一下从1n(这里我们说从什么到什么默认是从里到外)的顺序答案是什么。先以4个的为例,A4(A3(A2(A1+B1)+B2)+B3)+B4,拆括号,A1A2A3A4+B1A2A3A4+B2A3A4+B3A4+B4,看出规律了吗?w=1nAw+k=1n(Bkw=k+1nAw)(这个式子十分没有用,看前面那个足矣)。
考虑AiAi+1的顺序对答案的影响,先考虑它们的顺序对哪几项有影响(我们对项的标号以Bii为准,第一项我们标为第0项,我们可以认为B0=1),发现只有第i项和第i+1项受影响,i1之前的没有BiBi+1,有AiAi+1交换后不受影响,i+2之后的ABii+1就都不含了,也没有影响,ii+1项只看B就肯定会受影响。交换后本来Bi乘的变成了Bi+1乘,本来Bi+1乘的变成了Bi乘,肯定会受影响。(有点啰嗦。。。)
再看受了啥影响。之前的是BiAi+1Ai+2Ai+3+Bi+1Ai+2Ai+3,后来的是Bi+1AiAi+2Ai+3+BiAi+2Ai+3ii+1换一下),如果前面的小于后面的那么换了就更优(BiAi+1Ai+2Ai+3+Bi+1Ai+2Ai+3<Bi+1AiAi+2Ai+3+BiAi+2Ai+3),但是这个式子太长了,化简一下。
首先把Ai+2Ai+3约掉,BiAi+1+Bi+1<Bi+1Ai+Bi,这个时候已经可以排序了(写在cmp函数里),但是我继续化简了一下,BiAi+1+Bi+1<Bi+1Ai+BiBiAi+1Bi<Bi+1AiBi+1Bi(Ai+11)<Bi+1(Ai1)

那么现在我们只要在这个顺序里选k个即可。
考虑dp,用fi,j代表考虑到i,选了j个的最大函数值。考虑转移,如果第i个不选,那么就是fi1,j,如果选,就是fi1,j1Ai+Bi,取max即可。

神奇的代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,k;
int f[200005][15]; 
struct nd{
	int a,b;
}x[200005];

bool cmp(nd l,nd r){
	return l.b*(r.a-1) > r.b*(l.a-1);
}

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