2.21闲话 & solution『 有没有/谁/能够代替我』
上午有唐氏模拟赛,100/0/0/20
,rk7/15
,鉴定为最唐的一次
T1
签到题,思路很简单
-
题面
ame
是一个可爱的女孩子,她想要你帮她排序。 给定\(4\times n\)个数,要求将其分为\(n\)组,使得对于每组四个数 ,所有组中 的\(|a\times b-c\times d|\)和最大,求最大和。
排序,对于前\(2n\)大的,尽量把大的和大的相乘,后\(2n\)的把大的和小的相乘,然后两者相减即可
赛时没删sleep
的调试,但是我的sleep
是用for
循环代替的,而我开了O2
侥幸通过此题
天依$\text{'s Code}$
int n,a[N],ans;
inline bool cmp(int x,int y){
return x<y;
}
signed main() {
FastI>>n;
for(int i=1;i<=4*n;i++){
FastI>>a[i];
}
sort(a+1,a+1+4*n,cmp);
const int TianYi=n*2;
for(int i=4*n;i>TianYi;i-=2){
ans+=a[i]*a[i-1];
}
for(int i=TianYi,j=1;i>=j;i--,j++){
ans-=a[i]*a[j];
}
FastO<<ans;
}
T2
是二分+单调队列优化\(\text{dp}\)
看到题面直接就知道是二分了,再仔细看看\(dp\)也出来了,但是明显裸的\(dp\)过不去,考虑优化\(\text{dp}\)
观察\(\text{dp}\)的转移方程发现满足单调队列优化的形式,考虑单调队列优化\(\text{dp}\)
天依$\text{'s Code}$
int f[N][2],n,m,s,w[N];
pair<int,int>que[N];
int head=1,tail=0;
inline void clear(){
head=1,tail=0;
}
inline void change(int x,int id){
while(head<=tail&&que[tail].first<x)
tail--;
que[++tail]=make_pair(x,id);
}
inline int Get(int l){
while(head<=tail&&que[head].second<l)
head++;
if(head>tail)
return 0;
return que[head].first;
}
inline bool check(int sz){
memset(f,0,sizeof(f));
clear();
for(int i=1;i<=n;i++){
if(i>=sz)
change(max(f[i-sz][1],f[i-sz][0])+n-(i-sz),i-sz);
f[i][0]=max(f[i-1][1],f[i-1][0]);
f[i][1]=max(f[i][1],Get(i-w[i])+i-n);
}
if(max(f[n][0],f[n][1])<s) return 0;
else return 1;
}
signed main(){
FastI>>n;
for(int i=1;i<=n;i++) FastI>>w[i];
FastI>>s;s=ceil(n*1.0/100*s);
int l=1,r=n;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid-1;
}
FastO<<r;
}
T3
赛时以为是树上组合数学,正解是树状dp
蒜头君有一棵 n 个节点的树(即 n个节点,n−1 条边的无向连通图)。树的每个节点上都有一个宝藏。蒜头君准备大动干戈,拿到这些保证。
但是在拿宝藏之前,蒜头君发现了一个问题,由于树的边的材质问题,若两个节点被一条边直接连接,为了确保安全,那么这两个节点上的宝藏最多可以拿一个。
好在同样擅长化学的巨佬--花椰妹给了蒜头君一条特殊材质的边。蒜头君可以选定一条边并将这条边的材质替换成特殊材质的边,于是为了确保安全,被这条选定的边直接相连的两个节点上的宝藏最少拿一个。
蒜头君想知道,对于每一条边,若选定这条边替换成花椰妹送给他的特殊材质的边,在确保安全的情况下,有多少种拿的方法是可行的。
查看错误题解
但是题解是错误的,因为裸的树形dp
复杂度是\(O(n^2)\)无法通过此题
可以通过dfs
预处理降低复杂度,详情看DZ博客
唔,代码没有诶
T4
赛时打了暴力,然后去写题了
正解是二分+线段树+扫描线
,官方题解依然是过于简略的
查看过于简略的题解
这里是正确的题解
点击查看std
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int n, m;
int arr[MAXN];
int last[MAXN];
int nxt[MAXN];
long long answer[MAXN];
struct SegmentTree {
public:
int min, num;
long long sum;
class LazyTag {
public:
int cover, tim;
long long add;
inline LazyTag() {
cover = -1;
add = 0;
tim = 0;
}
inline LazyTag(const int cover): cover(cover) {
if (cover == -1) {
tim = 1;
}
}
} tag;
} sgt[MAXN << 2];
inline void PushUp(const int now) {
sgt[now].min = min(sgt[now << 1].min, sgt[now << 1 | 1].min);
}
void Build(const int now = 1, const int left = 0, const int right = m) {
if (left == right) {
sgt[now].num = sgt[now].min = last[left];
return;
}
Build(now << 1, left, (left + right) >> 1);
Build(now << 1 | 1, ((left + right) >> 1) + 1, right);
PushUp(now);
}
inline void Down(const SegmentTree::LazyTag tag,
const int now, const int left, const int right) {
sgt[now].sum += 1ll * sgt[now].num * tag.tim + tag.add;
if (~tag.cover) {
if (~sgt[now].tag.cover) {
sgt[now].tag.add += 1ll * sgt[now].tag.cover * tag.tim + tag.add;
} else {
sgt[now].tag.tim += tag.tim;
sgt[now].tag.add = tag.add;
}
sgt[now].num = sgt[now].min = tag.cover;
sgt[now].tag.cover = tag.cover;
} else {
if (~sgt[now].tag.cover) {
sgt[now].tag.add += 1ll * sgt[now].tag.cover * tag.tim;
} else {
sgt[now].tag.tim += tag.tim;
}
}
}
inline void PushDown(const int now, const int left, const int right) {
Down(sgt[now].tag, now << 1, left, (left + right) >> 1);
Down(sgt[now].tag, now << 1 | 1, ((left + right) >> 1) + 1, right);
sgt[now].tag = SegmentTree::LazyTag();
}
void Updata(const int now_left, const int now_right,
const int cover, const int now = 1,
const int left = 0, const int right = m) {
if (now_right < left || right < now_left) {
return;
}
if (now_left <= left && right <= now_right) {
Down(SegmentTree::LazyTag(cover), now, left, right);
return;
}
PushDown(now, left, right);
Updata(now_left, now_right, cover, now << 1, left, (left + right) >> 1);
Updata(now_left, now_right, cover,
now << 1 | 1, ((left + right) >> 1) + 1, right);
PushUp(now);
}
inline void Time() {
Down(SegmentTree::LazyTag(-1), 1, 1, m);
}
int Find(const int now_left, const int now_right,
const int val, const int now = 1,
const int left = 0, const int right = m) {
if (now_right < left || right < now_left || val <= sgt[now].min) {
return -1;
}
if (left == right && now_left <= left && right <= now_right) {
return left;
}
int result(Find(now_left, now_right, val, now << 1 | 1,
((left + right) >> 1) + 1, right));
return ~result ? result : Find(now_left, now_right,
val, now << 1, left, (left + right) >> 1);
}
void GetAnswer(const int now = 1, const int left = 0, const int right = m) {
if (left == right) {
answer[left] = sgt[now].sum;
return;
}
PushDown(now, left, right);
GetAnswer(now << 1, left, (left + right) >> 1);
GetAnswer(now << 1 | 1, ((left + right) >> 1) + 1, right);
}
int main() {
scanf("%d%d", &n, &m);
int last0 = 0;
long long answer0 = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
if (arr[i] == 0) {
answer0 += (i - last0 - 1ll) * (i - last0) >> 1;
last0 = i;
}
}
answer0 += (n - last0) * (n + 1ll - last0) >> 1;
for (int i = 0; i <= m; i++) {
last[i] = n + 1;
}
for (int i = n; i >= 1; i--) {
nxt[i] = last[arr[i]];
last[arr[i]] = i;
}
for (int i = 1; i <= m - 1; i++) {
last[i] = max(last[i], last[i - 1]);
}
Build();
for (int i = 1; i <= n; i++) {
Time();
int f = Find(arr[i], m, nxt[i]);
if (~f) {
Updata(arr[i], f, nxt[i]);
}
}
GetAnswer();
int l, r;
scanf("%d%d", &l, &r);
if (!l) {
printf("%lld ", answer0);
l = 1;
}
for (int i = l; i <= r; i++) {
printf("%lld ", answer[i] - answer[i - 1]);
}
return 0;
}