「11.03」 陶陶摘苹果(线段树)开心的金明(贪心)笨小猴(乱搞)
又考了一场试,昨天放假稍蒙比...,距离csps还有十天,希望比以前的自己更用心
A. 陶陶摘苹果
做法有很多,联想起以前考过的一个单调栈、倍增的题,然而我直接用的无脑线段树做法。
倒序建树离线储存答案,每次因为在修改点之前的决策不受影响,所以可以预处理前面的影响
后面的影响其实就是一个单调栈嘛.......
%%%%%%zzn,xkl用分块在线跑过
可以线段树维护单调栈,虽然两个log
#include<bits/stdc++.h> #define MAXN 2100000 #define inf 0x7ffffffffffff using namespace std; int read(){ char c=getchar();int x=0;int ff=1; while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*ff; } int m;struct node{int l,r,sum,w;}t[MAXN];int n,a[MAXN]; int cal(int k,int w){ if(t[k].l==t[k].r)return t[k].sum>w; if(t[k*2].sum>w)return cal(k*2,w)+t[k*2+1].w; else return cal(k*2+1,w); } void updata(int k){ t[k].sum=max(t[k*2].sum,t[k*2+1].sum); t[k*2+1].w=cal(k*2+1,t[k*2].sum); } void build(int k,int l,int r){ t[k].l=l;t[k].r=r; if(l==r){t[k].sum=a[l];return ;} int mid=(t[k].l+t[k].r)>>1; build(k*2,l,mid); build(k*2+1,mid+1,r); updata(k); } void add(int k,int x){ if(t[k].l==t[k].r){t[k].sum=a[t[k].l];return ;} int mid=(t[k].l+t[k].r)>>1; if(x<=mid)add(k*2,x); else add(k*2+1,x); updata(k); } signed main(){ freopen("TaoPApp.in","r",stdin); freopen("TaoPApp.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;++i)a[i]=read(); build(1,1,n); for(int i=1;i<=m;++i){ int pos=read();int h=read();int y=a[pos]; a[pos]=h; add(1,pos); printf("%d\n",cal(1,-1)); a[pos]=y; add(1,pos); } }
B. 开心的金明
一道很大神的贪心题。。。。。。
题面是在考我的语文阅读能力QAQ
首先对于原材料而言,他的成本对每个月而言都是可以提前算出来的
然后对于电脑而言一个时有储存的限制,一个是有生产的限制
考场上打的是$n*e_{i}$的DP,但是$e$的范围是$1e8$,当场去世,想写贪心却没有思路
首先需要知道一个性质,对于当前销售,销售成本更低的商品提前销售更优,
因为在不考虑储存限制的情况小,当前商品$->$下一个月都是加了一个$E_{i}$的值,也就是说他们的优先程度还是不变的
当我们现在选择最优的一定不会是结果更差。
然后我们每次都将全部生产,在以后的转移中如果发现可储存的值比较小,就舍弃掉成本最大的计算机,可以用一个堆来实现
至于$WA80$(也可能$WA10$)是因为可能存在当前的计算机总数小于当前的$e_{i}$数量
注意细节
1 #include<bits/stdc++.h> 2 #define MAXN 2100000 3 #define inf 0x7ffffffffffff 4 #define int long long 5 using namespace std; 6 int read(){ 7 char c=getchar();int x=0;int ff=1; 8 while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();} 9 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();} 10 return x*ff; 11 } 12 int c[MAXN];//原材料费用 13 int d[MAXN];//需求 14 int p[MAXN];//生产量 15 int m[MAXN];//电脑价钱 16 int e[MAXN];//电脑储存数 17 int R[MAXN];//原材料储存价钱 18 int E[MAXN];//电脑储存价钱 19 int n; 20 int noww[MAXN];int ok; 21 struct node{ 22 int val,sum,id; 23 friend bool operator <(node a,node b){ 24 return a.val>b.val; 25 } 26 }kx[MAXN]; 27 priority_queue<node>q; 28 bool cmp(node a,node b){ 29 return a.val>b.val; 30 } 31 int sum[MAXN]; 32 int ans=0; 33 signed main(){ 34 freopen("happy.in","r",stdin); 35 freopen("happy.out","w",stdout); 36 n=read(); 37 for(int i=1;i<=n;++i){ 38 c[i]=read();d[i]=read();m[i]=read();p[i]=read(); 39 } 40 for(int i=1;i<=n-1;++i){ 41 e[i]=read();R[i]=read();E[i]=read(); 42 } 43 noww[1]=c[1]; 44 for(int i=2;i<=n;++i){ 45 noww[i]=min(noww[i-1]+R[i-1],c[i]); 46 } 47 for(int i=1;i<=n;++i){ 48 q.push((node){noww[i]+m[i],p[i],i}); 49 sum[i]=p[i]; 50 ans+=(noww[i]+m[i])*p[i]; 51 int ned=d[i];int tot=0;int tsum=0; 52 while(!q.empty()){ 53 node x=q.top();q.pop(); 54 if(ned>=x.sum){ 55 ned-=x.sum; 56 sum[x.id]-=x.sum; 57 } 58 else{ 59 sum[x.id]-=ned;ned=0; 60 } 61 if(sum[x.id]!=0){ 62 kx[++tot].id=x.id; 63 kx[tot].sum=sum[x.id]; 64 kx[tot].val=x.val; 65 tsum+=sum[x.id]; 66 } 67 } 68 if(ned!=0){ok=1;break;} 69 sort(kx+1,kx+tot+1,cmp); 70 for(int j=1;j<=tot;++j){ 71 if(tsum<=e[i])break; 72 if(tsum-e[i]>=sum[kx[j].id]){ 73 ans-=kx[j].val*sum[kx[j].id]; 74 tsum-=sum[kx[j].id]; 75 sum[kx[j].id]=0; 76 } 77 else { 78 ans-=kx[j].val*(tsum-e[i]); 79 sum[kx[j].id]-=tsum-e[i]; 80 tsum=e[i]; 81 } 82 } 83 for(int j=1;j<=tot;++j){ 84 if(sum[kx[j].id]==0)continue; 85 q.push((node){kx[j].val+E[i],sum[kx[j].id],kx[j].id}); 86 } 87 ans+=tsum*E[i]; 88 } 89 if(ok==1)printf("-1"); 90 else printf("%lld\n",ans); 91 }
思路积累:
1.贪心思考,可以先加后来根据决策再减,类似反悔的过程
2.别死刚DP....
C. 笨小猴
由于某些sb理由考场随机化没有AC,注意结构体的下标与原下标的关系
然后可以瞎rand了....