bzoj1122:[POI2008]賬本BBB
阿新 • • 發佈:2019-02-16
ostream con max tdi 是我 pro algo 我們 i++
傳送門
異常激動,跑了bzoj的rank2
這個題一共有兩個要求,先考慮第二個要求,可以知道每一次修改都會導致答案賬戶余額+2/-2
所以修改方案是唯一的,可以\(O(1)\)算出來
然後考慮第一個要求,顯然有結論:如果當前值為負,你可以修改當前位置之前的一個負號為正號,並且修改當前位置之後的一個正號為負號來使最小值+2
然而你也可以移動最後的符號使最小值不小於0
於是我們就得出了一個算法:先算出需要修改多少個符號來滿足第二個要求,如果是將負號修改為正號,便可以將最小值升高,如果最小值依然小於0,那麽枚舉移動最後的數的個數,同時使用那個結論,得出最小的修改代價,統計到答案中
代碼:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; void read(int &x) { char ch; bool ok; for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1; for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x; } #define rg register const int maxn=1e6+10; int n,p,q,x,y,mp[maxn],sum[maxn],nsum[maxn],mx,now,mn,ans;char ch[maxn]; int main() { read(n),read(p),read(q),read(x),read(y),scanf("%s",ch+1); for(rg int i=1;i<=n;i++)mp[i]=ch[i]=='-'?-1:1,mx+=mp[i]; mx=(q-mx-p)/2,now=p,ans=abs(mx)*x; for(rg int i=1;i<=n;i++)now+=mp[i],mn=min(mn,now); if(mn<0) { if(mx>0)mn+=mx*2;now=0;int a=0,b=1e9; if(mn<0) { if(mn&1)b=(abs(mn)/2+1)*2*x; else b=abs(mn)/2*2*x; for(rg int i=n;i>=1;i--) { now+=mp[i];if(now+mn>=0){b=min(y*(n-i+1),b);break;} a=y*(n-i+1); if(mn+now<0) { int g=mn+now; if(g&1)a+=(abs(g)/2+1)*2*x; else a+=abs(g)/2*2*x; } b=min(b,a); } ans+=b; } } printf("%d\n",ans); }
bzoj1122:[POI2008]賬本BBB