CF1969
CF1969
D
Description
有
Alice 希望自己的利润最大化,而 Bob 希望 Alice 的利润最小化,求 Alice 能获得的最大利润。
Solution
首先忽略所有
考虑 Bob 会如何行动,为了使 Alice 收益最小,Bob 一定会免费拿走
考虑 Alice 会如何行动,设 Bob 拿走的物品
因此我们按照
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
struct node{
int a,b;
}d[N];
int T,n,k,num,sum[N],ans;
priority_queue<int>q;
bool cmp(node x,node y){
return x.b<y.b;
}
int read(){
int k=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
k=k*10+ch-'0',ch=getchar();
return k;
}
signed main(){
T=read();
while(T--){
n=read(),k=read();
ans=0;
for(int i=1;i<=n;i++)
d[i].a=read();
for(int i=1;i<=n;i++)
d[i].b=read();
sort(d+1,d+1+n,cmp);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1];
if(d[i].a<d[i].b)
sum[i]+=d[i].b-d[i].a;
}
num=0;
for(int i=n;i>=1;i--){
if(i<=n-k){
ans=max(ans,sum[i]-num);
q.push(d[i].a);
num+=d[i].a-q.top();
q.pop();
}
else{
num+=d[i].a;
q.push(d[i].a);
}
}
printf("%lld\n",ans);
while(!q.empty())
q.pop();
}
return 0;
}
E
Description
定义一个子段是独特子段,当且仅当存在一个整数在这个子段中出现恰好一次。
给定序列
Solution
考虑扫描线,定义一个二维平面,横轴代表左端点,纵轴代表右端点,点
依次考虑每一个点,设
则对于所有
我们从右到左扫描线,设当前扫描到左端点
感性证明一下,将
由于是从右到左的扫描线,当扫描到
Code
#include <bits/stdc++.h>
#define ls k<<1
#define rs k<<1|1
using namespace std;
const int N=3e5+5;
struct node{
int l,r,k;
};
int T,n,a[N],b[N],pr[N],sf[N],ans;
int mi[N<<2],tag[N<<2];
vector<node>e[N];
int read(){
int k=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
k=k*10+ch-'0',ch=getchar();
return k;
}
void pushup(int k){
mi[k]=min(mi[ls],mi[rs]);
}
void pushdown(int k){
if(tag[k]){
mi[ls]+=tag[k],tag[ls]+=tag[k];
mi[rs]+=tag[k],tag[rs]+=tag[k];
tag[k]=0;
}
}
void build(int k,int l,int r){
tag[k]=0;
if(l==r){
mi[k]=0;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(k);
}
void modify(int k,int l,int r,int x,int y,int v){
if(x>y) return;
if(x<=l&&r<=y){
mi[k]+=v,tag[k]+=v;
return;
}
pushdown(k);
int mid=(l+r)>>1;
if(x<=mid) modify(ls,l,mid,x,y,v);
if(mid+1<=y) modify(rs,mid+1,r,x,y,v);
pushup(k);
}
int main(){
T=read();
while(T--){
ans=0;
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++){
pr[i]=b[a[i]];
b[a[i]]=i;
}
for(int i=1;i<=n;i++) b[i]=n+1;
for(int i=n;i>=1;i--){
sf[i]=b[a[i]];
b[a[i]]=i;
}
for(int i=1;i<=n;i++) b[i]=0;
for(int i=1;i<=n;i++){
e[pr[i]].push_back((node){i,sf[i]-1,-1});
e[i].push_back((node){i,sf[i]-1,1});
}
build(1,1,n);
for(int i=n;i>=1;i--){
for(node j:e[i])
modify(1,1,n,j.l,j.r,j.k);
modify(1,1,n,1,i-1,1);
if(mi[1]==0){
modify(1,1,n,i,n,1);
ans++;
}
modify(1,1,n,1,i-1,-1);
}
printf("%d\n",ans);
for(int i=0;i<=n;i++)
e[i].clear();
}
return 0;
}
F
Description
给定一个大小为
初始摸
Solution
首先有结论,若手中有两张一样的牌,则打出这两张牌一定是不劣的。
因为若将两张
考虑当前手牌中没有两张一样的牌是什么情况,一定是所有
尝试 dp,设
每次转移枚举打出的手牌,再暴力判断是或否合法,时间复杂度
我们发现枚举打出的手牌非常劣,因为只有较少的情况是合法的。
准确来说,从
进一步,若在
因此每次转移的时候,我们枚举转移点并且维护后续手牌的奇偶性,仅在有两个类型的手牌个数为奇数时转移。
还有一种情况,若自
剩下的牌中第
由于是向下取整,因此我们优先出
时间复杂度
Code
(待续)