CF853
CF853A
容易想到的贪心思路:每次让c值最大的先飞。
区间取最大值&带修 可以线段树/堆维护
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define ll long long
#define endl '\n'
#define int ll
#define ls k<<1
#define rs k<<1|1
#define mid (l+r>>1)
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x3f3f3f3f;
const int base=131;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
inl void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar(endl);}
bool st;
int n,k,c[N],sum,ans,m,res[N];
bool ed;
struct segtree{
int ma[N<<2],pos[N<<2],idx[N<<2];
inl void pushup(int k){
if(ma[ls]>=ma[rs]){
pos[k]=pos[ls];
ma[k]=ma[ls];
idx[k]=idx[ls];
}else{
pos[k]=pos[rs];
ma[k]=ma[rs];
idx[k]=idx[rs];
}
}
inl void build(int k,int l,int r){
if(l==r)return pos[k]=l,ma[k]=c[l],idx[k]=l,void();
build(ls,l,mid);build(rs,mid+1,r);
pushup(k);
}
inl void modify(int k,int l,int r,int x,int v,int id){
if(l==r)return ma[k]=v,idx[k]=id,void();
if(x<=mid)modify(ls,l,mid,x,v,id);
else modify(rs,mid+1,r,x,v,id);
pushup(k);
}
}SGT;
signed main(){
n=read();k=read();
for(int i=1;i<=n;i++)c[i]=read();
for(int i=2;i<=k+1;i++){
if(i-1<=n)sum+=c[i-1];
ans+=sum;
}
if(k+1<=n)sum+=c[k+1];
m=min(k+1,n);
SGT.build(1,1,m);
for(int i=1;i<=n-m;i++){
int x=SGT.pos[1],v=SGT.ma[1],id=SGT.idx[1];
sum-=v;ans+=sum;sum+=c[k+1+i];res[id]=k+i;
SGT.modify(1,1,m,x,c[k+1+i],k+1+i);
}
for(int i=1;i<=m;i++){
int x=SGT.pos[1],v=SGT.ma[1],id=SGT.idx[1];
sum-=v;ans+=sum;res[id]=k+n-m+i;
SGT.modify(1,1,m,x,0,0);
}
writel(ans);
for(int i=1;i<=n;i++)writei(res[i]);
return 0;
}
CF853B
维护每个时间能到的人数/总共花费 求出最早所有人都能到的时间 离开同理
贪心即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define ll long long
#define endl '\n'
#define int ll
const int N=1e6+5;
const int M=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int base=131;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
inl void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar(endl);}
bool st;
int n,m,k,d,f,tt,c,csta[N],cstb[N],cnt,s,t,a[N],b[N],ans=inf;
vector<pair<int,int>>come[N],leave[N];
bool ed;
signed main(){
n=read();m=read();k=read()+2;
for(int i=1;i<=m;i++){
d=read();f=read();tt=read();c=read();
if(!tt)come[d].push_back({f,c});
else leave[d].push_back({tt,c});
}
for(int i=1;i<=1e6;i++){
a[i]=a[i-1];
for(auto j:come[i]){
int x=j.first,v=j.second;
if(!csta[x])cnt++,a[i]+=v,csta[x]=v;
else if(v<csta[x])a[i]+=v-csta[x],csta[x]=v;
}
if(!s&&cnt==n)s=i;
}
cnt=0;
for(int i=1e6;i;i--){
b[i]=b[i+1];
for(auto j:leave[i]){
int x=j.first,v=j.second;
if(!cstb[x])cnt++,b[i]+=v,cstb[x]=v;
else if(v<cstb[x])b[i]+=v-cstb[x],cstb[x]=v;
}
if(!t&&cnt==n)t=i;
}
if(!s||!t||t-s+1<k){puts("-1");return 0;}
for(int i=s;i+k-1<=t;i++)ans=min(ans,a[i]+b[i+k-1]);
writel(ans);
return 0;
}
CF853C
n个点好矩阵的个数:\(n*(n-1)/2\)
考虑容斥:用右上角的数量-左上角左边-右下角下边+左下角下边
二位数点 树状数组离线求即可
口胡完毕 代码咕了
CF853D
发现所有 \(a_i\) 除100之后没有影响
考虑dp:攒积分/花积分两种分别转移
这里积分最多攒到40 再多就没必要了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define ll long long
#define endl '\n'
#define int ll
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int base=131;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
inl void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar(endl);}
bool st;
int n,a[N],f[N][45];
bool ed;
signed main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read()/100;
memset(f,0x3f,sizeof f);
f[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=40;j++){
if(j-a[i]/10>=0)f[i][j]=min(f[i][j],f[i-1][j-a[i]/10]+a[i]);
for(int k=0;k<=a[i]&&k+j<=40;k++)
f[i][j]=min(f[i][j],f[i-1][j+k]+a[i]-k);
}
}
int ans=inf;
for(int i=0;i<=40;i++)ans=min(ans,f[n][i]);
writel(ans*100);
return 0;
}
E题3400不会不丢人/kel

浙公网安备 33010602011771号