打铁回来刷水。
链接:
[1107E]Vasya and Binary String
[1107G]Vasya and Maximum Profit
[1107F]Vasya and Endless Credits
区间DP然后中间你发现要套一个背包。然后你发现你写成了n五方(??)
然后冷静分析发现L相等的那个背包可以一起跑,于是就成n四方了(貌似空间比标程少一个n?)
#include
using namespace std;
const int N=110;
typedef long long ll;
int n;
char t[N];
int pre[N];
int c[N];
ll f[N][N];
ll g[2][N][N];
const int INF=0x3f3f3f3f;
void upd(ll &A,ll B){A=max(A,B);}
int main()
{
scanf("%d",&n);
scanf("%s",t+1);
for(int i=1;i<=n;i++)pre[i]=pre[i-1]+t[i]-'0';
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int l=n;l;l--){
for(int i=1;i<=n;i++)g[0][l-1][i]=g[1][l-1][i]=-INF;
g[0][l-1][0]=g[1][l-1][0]=0;
for(int i=l;i<=n;i++){
int mx=i-l+1;
for(int j=0;j<=mx;j++)g[0][i][j]=g[1][i][j]=-INF;
if(t[i]=='1'){
for(int j=1;j<=mx;j++) g[1][i][j]=g[1][i-1][j-1];
}else{
for(int j=1;j<=mx;j++) g[0][i][j]=g[0][i-1][j-1];
}
for(int len=l+1;len<=i;len++)for(int j=0;j<=mx;j++){
upd(g[0][i][j],g[0][len-1][j]+f[len][i]);
upd(g[1][i][j],g[1][len-1][j]+f[len][i]);
}
ll MX=0;
for(int j=0;j<=mx;j++){
MX=max(MX,max(g[0][i][j],g[1][i][j])+(ll)c[j]);
}
f[l][i]=(l==i)?(c[1]):MX;
upd(g[0][i][0],f[l][i]); upd(g[1][i][0],f[l][i]);
}
}
cout<
开个单调栈开个线段树没了
#include
using namespace std;
typedef long long ll;
int n;ll a;
const int N=3e5+5;
ll delt[N],d[N],c[N];
struct SegT{
ll t[N<<2],lzy[N<<2];
inline void build(int x,int l,int r){
int mid=(l+r)>>1;
if(l==r){
t[x]=-c[l-1]+a*(ll)(l-1);//L
return ;
}
t[x]=min(t[x<<1],t[x<<1|1]);
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
inline void pushdown(int x,int l,int r){
if(lzy[x]){
t[x]+=lzy[x];
if(l^r)lzy[x<<1]+=lzy[x],lzy[x<<1|1]+=lzy[x];
lzy[x]=0;
}
}
inline void modify(int x,int l,int r,int ql,int qr,ll val){
pushdown(x,l,r);
int mid=(l+r)>>1;
if(ql<=l&&qr>=r){
lzy[x]+=val;
return;
}
if(ql<=mid)modify(x<<1,l,mid,ql,qr,val);
if(qr>mid)modify(x<<1|1,mid+1,r,ql,qr,val);
pushdown(x<<1,l,mid),pushdown(x<<1|1,mid+1,r);
t[x]=min(t[x<<1],t[x<<1|1]);
}
inline ll qry(int x,int l,int r,int ql,int qr){
pushdown(x,l,r);
ll ans=1e18;
if(ql<=l&&qr>=r)return t[x];
int mid=(l+r)>>1;
if(ql<=mid)ans=min(ans,qry(x<<1,l,mid,ql,qr));
if(qr>mid)ans=min(ans,qry(x<<1|1,mid+1,r,ql,qr));
return ans;
}
}T;
ll stk[N];
int top;
int pos[N];
ll ans=0;
int main()
{
scanf("%d%lld",&n,&a);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&d[i],&c[i]);
delt[i]=(ll)(d[i]-d[i-1])*(d[i]-d[i-1]);
}
for(int i=1;i<=n;i++){c[i]+=c[i-1];}
T.build(1,1,n);
for(int R=1;R<=n;R++){
if(R>1){
int rr=R-2;
T.modify(1,1,n,R-1,R-1,delt[R]);
while(top&&stk[top]<=delt[R]){
int ll=pos[top-1]+1;
T.modify(1,1,n,ll,rr,delt[R]-stk[top]);
rr=pos[top-1];
top--;
}
stk[++top]=delt[R];
pos[top]=R-1;
}
ll ret=T.qry(1,1,n,1,R);
ll Rsum=a*(ll)R-(ll)c[R];
ans=max(ans,Rsum-ret);
}
printf("%lld\n",ans);
}
upd
发现条件差不多就是每个时间/每个位置只能选1次,然后就是一个二分图最大匹配了。
然后一发费用流自闭了
然后粘的KM板子也自闭了
最后粘题解的KM板子才过貌似有dp做法。
然而并不会
#include
using namespace std;
typedef long long ll;
const int MAXN = 510;
const ll INF = 10000000000000000LL;
const ll inf = 5000000000000LL;
int n;
int nx, ny;
int times;
ll v[MAXN][MAXN];
ll ex[MAXN], ey[MAXN];
ll slack[MAXN];
int ux[MAXN], uy[MAXN], mx[MAXN], my[MAXN], pre[MAXN];
template
inline void freshmin(T &a, const T &b)
{
if (a > b) a = b;
}
void match(int y)
{
while (y)
{
my[y] = pre[y];
swap(y, mx[pre[y]]);
}
}
void bfs(int sx)
{
for (int y = 1; y <= ny; ++ y)
slack[y] = INF;
queue Q;
Q.push(sx);
++ times;
while (1)
{
while (!Q.empty())
{
int x = Q.front();
Q.pop();
ux[x] = times;
ll gap;
for (int y = 1; y <= ny; ++ y)
if (uy[y] != times && (gap = ex[x]+ey[y]-v[x][y]) <= slack[y])
{
pre[y] = x;
if (!gap)
{
uy[y] = times;
if (!my[y])
return match(y);
else
Q.push(my[y]);
}
else
slack[y] = gap;
}
}
ll d = INF;
for (int y = 1; y <= ny; ++ y)
if (uy[y] != times) freshmin(d, slack[y]);
for (int x = 1; x <= nx; ++ x)
if (ux[x] == times) ex[x] -= d;
for (int y = 1; y <= ny; ++ y)
if (uy[y] == times) ey[y] += d; else slack[y] -= d;
for (int y = 1; y <= ny; ++ y)
if (uy[y] != times && !slack[y])
{
uy[y] = times;
if (!my[y])
return match(y);
else
Q.push(my[y]);
}
}
}
void KM()
{
for (int y = 1; y <= ny; ++ y)
{
my[y] = 0;
ey[y] = 0;
uy[y] = 0;
}
for (int x = 1; x <= nx; ++ x)
{
mx[x] = 0;
ex[x] = *max_element(v[x]+1, v[x]+ny+1);
ux[x] = 0;
}
for (int x = 1; x <= nx; ++ x)
bfs(x);
ll ans = 0;
for (int y = 1; y <= ny; ++ y)
ans += v[my[y]][y];
cout << ans << endl;
}
int main()
{
scanf("%d",&n);
for(ll x=1;x<=n;x++){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
for(ll i=1;i<=n;i++){
ll tm=i-1;
tm=min(c,tm);
ll p=a-b*tm;
if(p>0)v[x][i]=p;
}
}
nx=ny=n;
KM();
}