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(wi−wx)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+1∗bi的价值
然后一开始可以选择一段区间的二元组,然后把它们每个都乘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就可以了????
过分
暂且咕着,官方题解没出