Comet OJ - Contest #8

Comet OJ - Contest #8
第一次打,感觉好赤鸡
然后就凉了

T1

大意就是说给出n个字符串,然后求出字典序最小的那个
……这也太签到了吧

T2

给出一个 w w w数组,对每个 x x x
∑ i = 1 n ( w i − w x ) 2 \sum_{i=1}^n{(w_i-w_x)^2} i=1n(wiwx)2

把式子拆开一下就是道水题了呀

T3

题意就是给出n个二元组 ( a i ,   b i ) (a_i,\ b_i) (ai, bi),然后每次可以把相邻的两个二元组合并
即将 ( a i ,   b i ) (a_i,\ b_i) (ai, bi) ( a i + 1 ,   b i + 1 ) (a_{i+1},\ b_{i+1}) (ai+1, bi+1)合并成 ( a i ,   b i + 1 ) (a_i,\ b_{i+1}) (ai, bi+1),然后产生 a i + 1 ∗ b i a_{i+1}*b_i ai+1bi的价值
然后一开始可以选择一段区间的二元组,然后把它们每个都乘k(给出的),最小化最后合并的权值

也不难,就是看错题见祖宗了 注意到这个合并规则,发现最终的权值并不会收到合并顺序的影响,然后就可以把式子先列出来,拆一拆然后对于每个右端点就找最优决策的左端点就好了
code:

#include<bits/stdc++.h>
#define INF 1e18
using namespace std;
long long n, k, sum[1000005], a[1000005], b[1000005];
int main(){
	ios::sync_with_stdio(false);
	cin >> n >> k;
	for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i], sum[i] = sum[i - 1] + b[i - 1] * a[i];//先记一个前缀和
	long long mi = INF, ans = sum[n];
	for(int i = 1; i <= n; i ++){
		mi = min(mi, b[i - 1] * a[i] * k - sum[i] * k * k + sum[i - 1]);//找最优的左端点
		ans = min(ans, sum[i] * k * k + mi + b[i] * a[i + 1] * k + sum[n] - sum[min(n, i + 1ll)]);//更新答案
	}
	cout << ans;
	return 0;
}

T4

大意,很难描述,自己看题吧
发现一个点连出的边所对应的点最多只有两个是有用的,即左边到当前点最近的点 l l l 和右边到当前点最近的点 r r r
然后就这个点能对左右端点在 l , r l,r l,r之间且包含这个点的询问产生贡献,然后直接把所有的询问离线,按照右端点排序,然后树状数组维护一个差分前缀和序列就好了
code:

#include<bits/stdc++.h>
#define lowbit(x) (x & -x)
#define int long long
#define N 2000005
using namespace std;
struct qq{
	int l, r, id;
}q[N];
int cmp(qq x, qq y){
	return x.r < y.r;
}
int tree[N];
void update(int x, int y){
	if(!x) return;
	for(;x < N; x += lowbit(x)) tree[x] += y;
}
int query(int x){
	int ret = 0;
	for(;x; x -= lowbit(x)) ret += tree[x];
	return ret;
}
int n, m, Q, ANS[N], L[N], R[N], a[N];
vector<int> del[N];
signed main(){
	scanf("%lld%lld%lld", &n, &m, &Q);
	for(int i = 1; i <= n; i ++){
		scanf("%lld", &a[i]);
		R[i] = n, L[i] = 1;
	}
	for(int i = 1; i <= m; i ++){
		int u, v;
		scanf("%lld%lld", &u, &v);
		if(v < u) L[u] = max(L[u], v + 1);
		else R[u] = min(R[u], v - 1);//左右端点
	}
	for(int i = 1; i <= n; i ++) del[R[i] + 1].push_back(i);//过了右端点就要把之前的删了
	
	for(int i = 1; i <= Q; i ++) scanf("%lld%lld", &q[i].l,  &q[i].r), q[i].id = i;//离线询问
	
	sort(q + 1, q + 1 + Q, cmp);
	
	int pos = 0;
	for(int i = 1; i <= Q; i ++){
		int l = q[i].l, r = q[i].r;
		for(int j = pos + 1; j <= r; j ++) update(L[j] - 1, - a[j]), update(j, a[j]);//差分
		for(int j = pos + 1; j <= r; j ++){
			for(int k = 0; k < del[j].size(); k ++){
				int id = del[j][k];
				update(L[id] - 1, a[id]), update(id, - a[id]);//删除
			}
		}
		pos = r;
		ANS[q[i].id] = query(r) - query(l - 1);//询问
	}
	int anss = 0;
	for(int i = 1; i <= Q; i ++) anss ^= ANS[i] * i;//输出(按照题目要求
	printf("%lld", anss);	
	return 0;
}

T5

题面说得很清楚
考场上想用杜教筛大力艹过去,但发现时间复杂度不对,然后就咕了

听说直接暴力打个表然后上OEIS就可以了????
过分
暂且咕着,官方题解没出

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值