2026贪心HDU大改革 HDU20260820I
WZH HDU20260820I 大改革
拿下首杀!!!!!!!!!
题目描述:
有 n 个变量,第 i 个变量为 ti ,有权重 ai,bi 。有三个变量 S1,S2,A ,初始为 0 。
你可以以任意顺序,对于每一个满足 ti=0 的 i 依次执行以下两个操作:
- 若 ai=ti ,则令 A←A+[S1≥c]+[S1≥−c] ,然后令 S1←S1+1 。否则令 A←A−[S1≤c]−[S1≤−c] ,然后令 S1←S1−1 。
- 若 bi=ti ,则令 A←A+[S2≥c]+[S2≥−c] ,然后令 S2←S2+1 。否则令 A←A−[S2≤c]−[S2≤−c] ,然后令 S2←S2−1 。
求 A 最大值。
n,c≤104 。
ti,ai,bi∈{−1,0,1} 。
对于每一个 ti=0 的 i ,将他们分为三类:
- ai=bi=ti 。
- ai=ti=bi 或 bi=ti=ai 。
- ai=ti 且 bi=ti 。
很明显,如果先执行二类操作,那么由于价值和损失的对称性,可以知道 A 几乎就是 0 ,所以我们应该按照一二三的顺序执行操作。
一类和三类的操作是固定的,所以决策主要发生在二类操作。
我们充分发扬人类智慧:
根据数学直觉,最优解必定先让 S1 或 S2 疯涨到 c 然后交替操作。
这样做跑的飞快,连 n=104 时都可以在 400ms 内搞定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <bits/stdc++.h> using namespace std; const int N=100010; int T,n,c,a[N],b[N],t[N]; int get1(int x){return (x>=c)+(x>=-c);} int get2(int x){return -(x<=c)-(x<=-c);} void WZH(){ scanf("%d%d",&n,&c); for(int i=1;i<=n;i++)scanf("%d%d%d",t+i,a+i,b+i); int ans=0,S1=0,S2=0; for(int i=1;i<=n;i++)if(t[i]&&a[i]==t[i]&&b[i]==t[i]) ans+=2*get1(S1),S1++,S2++; int cnt1=0,cnt2=0; for(int i=1;i<=n;i++)if(t[i]&&a[i]==t[i]&&b[i]!=t[i])cnt1++; for(int i=1;i<=n;i++)if(t[i]&&b[i]==t[i]&&a[i]!=t[i])cnt2++; int flag=0; if(max(cnt1,cnt2)>c-S1){ int lim=c-S1+1; if(lim>0){ for(int i=1;i<=lim;i++){ if(cnt1>cnt2)ans+=get1(S1)+get2(S2),S1++,S2--; else ans+=get2(S1)+get1(S2),S1--,S2++; } if(cnt1>cnt2)cnt1-=lim,flag=1; else cnt2-=lim,flag=2; } } if(cnt1==cnt2){ for(int i=1;i<=cnt1*2;i++){ if(i&1^(flag==2))ans+=get1(S1)+get2(S2),S1++,S2--; else ans+=get1(S2)+get2(S1),S1--,S2++; } } else if(cnt1<cnt2){ for(int i=1;i<=cnt1*2;i++){ if(i&1^(flag==2))ans+=get1(S1)+get2(S2),S1++,S2--; else ans+=get1(S2)+get2(S1),S1--,S2++; } for(int i=cnt1+1;i<=cnt2;i++)ans+=get1(S2)+get2(S1),S2++,S1--; } else{ for(int i=1;i<=cnt2*2;i++){ if(i&1^(flag==2))ans+=get1(S1)+get2(S2),S1++,S2--; else ans+=get1(S2)+get2(S1),S1--,S2++; } for(int i=cnt2+1;i<=cnt1;i++)ans+=get1(S1)+get2(S2),S1++,S2--; } for(int i=1;i<=n;i++)if(t[i]&&a[i]!=t[i]&&b[i]!=t[i]) ans+=get2(S1)+get2(S2),S1--,S2--; printf("%d\n",ans); } int main(){ scanf("%d",&T); while(T--)WZH(); return 0; }
|