ABC379

C

link

由于只能往后放,显而易见,如果可以达到要求,那么一定只有一种方式。所以重心就在判断是否可行上了。
首先,如果总数量不等于\(n\)肯定不行。
其次,如果第一堆不在\(1\)肯定不行。
最后,如果到了某个点的时候石头总和不够\(1\)到这个点的数量一定是不行的。
那么在统计答案的时候,我们要把从这一个“石头根据地”到下一个“石头根据地”中间的都用当前这个上的石头填满,剩下的移动到下一个“石头根据地”上,因为是正好的,所以如果用不完肯定是后面缺,留以后用,再者如果不移动到后面放着也没用。
\(tips\):简化一下第三个判断,我们就直接照着统计答案时候的走,如果移动到下一个“石头根据地”的是负数,那么一定是累加到这一个就不够了,就是不行。(正数为有剩余,\(0\)为刚好,负数为不够了)

一定要排序

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

#define int long long

using namespace std;

int n,m;
struct nd{
	int x,a;
}y[200005];
int qzh;
int ans;

bool cmp(nd l,nd r){
	return l.x < r.x;
}

signed main(){
	
	cin >> n >> m;
	for(int i = 1;i <= m;++ i)
		cin >> y[i].x;
	for(int i = 1;i <= m;++ i)
		cin >> y[i].a,qzh = qzh+y[i].a;
	sort(y+1,y+1+m,cmp);
	
	y[m+1].x = n+1;
	
	if(qzh != n){
		cout << -1;
		return 0;
	}
	if(y[1].x != 1){
		cout << -1;
		return 0;
	}
	
	for(int i = 1;i <= m;++ i){
		int gs = y[i+1].x-1-y[i].x;
		ans += (1+gs)*gs/2;
		gs = y[i].a-gs-1;
		if(gs < 0){
			cout << -1;
			return 0;
		}
		ans += gs*(y[i+1].x-y[i].x);
		y[i+1].a += gs;
	}
	
	cout << ans;
	
	return 0;
	
}

D

link

其实\(10^{100}\)个花瓶并没有用,只是告诉你花瓶够用。
对于每一个花瓶,我们记录是在哪一个时刻种上的并用小根堆维护种上的时刻并记录当前时间即可做这三种操作。
第一种操作:新增一个时刻。
第二种操作:时间戳增加。
第三种操作:因为是小根堆,所以可以取出时间最小的(但由于一定是按时间顺序加入的,所以其实数组也行),判断一下时间最小的是否够了高度,即和当前时间的差是否大于要求高度,如果符合,收获这个,弹出,再找最小的。

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

#define int long long

using namespace std;

int q,t;
priority_queue<int,vector<int>,greater<int> > h;

signed main(){
	
	cin >> q;
	
	while(q--){
		int op,x;
		cin >> op;
		if(op == 1) h.push(t);
		else if(op == 2){
			cin >> x;
			t += x;
		}
		else if(op == 3){
			cin >> x;
			int g = t-x,ans = 0;
			while(!h.empty()){
				int w = h.top();
				if(w <= g) h.pop(),ans++;
				else break;
			}
			cout << ans << endl;
		}
	}
	
	return 0;
	
}

E

link

其实不是很难,只是有一点点复杂。
首先我们列一个样例看一下

25374
2
25
253
2537
25374
5
53
537
5374
3
37
374
7
74
4

自己手动对齐一下。。。
那我们发现,\(s_1\)做为个十百千万位各出现一次。\(s_2\)做为个十百千位各出现两次。……\(s_5\)做为各位出现了五次。换成一个表格就是:

规律就显而易见了,但不是很好描述,所以就不描述了。
那么结果就是\(s_1*11111(n个1)+s_2*2222(n-1个2)\) \(+……+s_n*n(1个n)\) \(= s_1*1*10^{n-1}+s_1*1*10^{n-2}\) \(+s_1*1*10^{n-3}+……+s_1*10+s_1*1+……+\) \(s_{n-1}*(n-1)*10+s_{n-1}*(n-1)*1+s_n*n*1\) \(= s_1*1*10^{n-1}\) \(+(s_1*1+s_2*2)*10^{n-2}+(s_1*1+s_2*2+s_3*3)*10^{n-3}\) \(+……+(s_1*1+s_2*2+s_3*3+……+s_n*n)*1\)
如果我们把每一项的系数(那个不是\(10\)的几次方的那个)看做个位数的话,感性理解一下,那么我们可以把这个式子近似的看成一个个位是\(s_1*1+s_2*2+……+s_n*n\),十位是\(s_1*1+s_2*2+……+s_{n-1}*(n-1)\),百位是\(s_1*1+s_2*2+……+s_{n-2}*(n-2)\),……最高位是\(s_1*1\)的一个\(n\)位数。
看似不是很有用的样子,但是,这道题要用高精度,那么这个东西就很有用了,我们拿一个数组存一下“每一位”,在进位即可,存每一位的时候可以从高到低,这样每次加一个\(s_i\)即可。

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

using namespace std;

int n;
char s[200005];
long long qzh;
long long x[3000005],cn;

signed main(){
	
	cin >> n >> s+1;
	
	for(int i = 1;i <= n;++ i)
		qzh += (s[i]-'0')*i;
	
	for(int i = n;i >= 1;-- i){
		x[++cn] = qzh;
		x[cn] += x[cn-1]/10;
		x[cn-1] %= 10;
		qzh -= (s[i]-'0')*i;
	}
	
	while(x[cn] >= 10){
		cn++;
		x[cn] += x[cn-1]/10;
		x[cn-1] %= 10;
	}
	
	for(int i = cn;i >= 1;-- i)
		cout << x[i];
	
	return 0;
	
}

F

link

首先要理解题意才能做题,相信你们都理解题意了,这里就不在赘述了。。。
首先我们观察一下,如果一个在\(r\)右边的\(i\)可以被\(l\)\(r\)同时看到,那么一定有\(max{h_{r+1},h_{r+2},……,h_{i-1}} \leq h_i\)\(max{h_{l+1},h_{l+2},……,~h_{i-1}} \leq h_i\),可以发现,后一个条件严格包含前一个条件,所以不管后一个条件即可。这时,一个任意的\(i\)\(l\)\(r\)同时看到的条件就是\(max{h_{l+1},h_{l+2},……,~h_{i-1}} \leq h_i\)\(i > r\)
先不看后一个条件怎么做?离线,把每一个\(r\)挂在\(l\)上,从后往前扫一个单调栈,存的是从前面能看到的,也就是说,如果来了一个比栈顶大的,栈顶又一定在当前数的后面,被当前数一挡,就看不见了,那么就可以把栈顶弹出了,因为前面的看不到它了,然后在每一个\(l\)的时候当前在栈里的所有的就都是满足第一个条件的了(能被\(l\)看到,没有被挡,因为如果挡了就弹出了)。
首先明确一个事,在栈里的一定是单调的,因为从后往前有顺序的加(栈里存的是下标)。
再考虑第二个条件,我们说了,栈是单调的,所以我们可以二分一下下标大于\(r\)的第一个数,那么这个数到栈底就都符合第二个条件,加上栈里的都符合第一个条件,这些数就是所有符合条件的了。
在每一个\(l\)上二分每一个\(r\)即可。

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

using namespace std;

int n,q;
int h[200005];
vector<pair<int,int> > ques[200005];
int st[200005],tp;
int ans[200005];

int ef(int x){
	int l = 0,r = tp;
	while(l < r){
		int mid = (l+r+1)/2;
		if(st[mid] > x) l = mid;
		else r = mid-1;
	}
	return l;
}

signed main(){
	
	cin >> n >> q;
	for(int i = 1;i <= n;++ i)
		cin >> h[i];
	for(int i = 1;i <= q;++ i){
		int l,r;
		cin >> l >> r;
		ques[l].push_back({r,i});
	}
	
	for(int i = n;i >= 1;-- i){
		if(ques[i].size()){
			for(int j = 0;j < ques[i].size();++ j){
				ans[ques[i][j].second] = ef(ques[i][j].first);
			}
		}
		while(tp&&h[st[tp]] <= h[i]) tp--;
		st[++tp] = i;
	}
	
	for(int i = 1;i <= q;++ i)
		cout << ans[i] << endl;
	
	return 0;
	
}
posted @ 2024-11-11 21:00  校牌杀手  阅读(63)  评论(0编辑  收藏  举报