标签:单调队列 containe com rac ble name des 暴力 位置
断环为链。
注意到两座仓库的距离不超过 \(\lfloor \frac{n-1}2 \rfloor\), 所以可以枚举算出每个仓库的最大可能代价, 然后用单调队列优化下就可以 \(O(N)\) 了(单调队列里的每个点都记录其 \(A\) 和其在链中的位置)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+15;
int n, a[N*2+5];
int q[N*2+5], he, ta;
int ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
a[n+i]=a[i];
}
q[he=ta=1] = 1;
for(int i=2;i<=(n<<1);++i) {
while(he<=ta && i-q[he]>(n-1)/2) ++he;
if(he<=ta) ans=max(ans, a[i]+a[q[he]]+i-q[he]);
while(he<=ta && a[q[ta]]-q[ta]<=a[i]-i) --ta;
q[++ta] = i;
}
cout << ans;
return 0;
}
首先建有向图, 边从先修课指向本课程, 发现建出了森林。
对每棵树分别求解在其中选 \([0,m]\) 个课程能拿到的最大得分, 最后用背包合并即可。
对每棵树求解的方法也用背包做。
#include<bits/stdc++.h>
using namespace std;
const int N = 305;
int n,m,sc[N];
vector<int> sons[N];
int f[N][N];
void sol(int x) {
f[x][0] = 0;
if(!sons[x].empty()) {
for(int i=0;i<(int)sons[x].size();++i) {
int y=sons[x][i];
sol(y);
for(int j=m;j>=1;--j)
for(int k=1;k<=j;++k)
f[x][j] = max(f[x][j], f[x][j-k]+f[y][k]);
}
}
if(x!=0) {
for(int i=m;i>=1;--i)
f[x][i] = f[x][i-1]+sc[x];
}
}
int main()
{
scanf("%d%d", &n,&m);
for(int i=1;i<=n;++i) {int fa;
scanf("%d%d", &fa,&sc[i]);
sons[fa].push_back(i);
}
sol(0);
cout << f[0][m];
return 0;
}
把 \(|D-P|\) 塞进状态里, 求最大 \(D+P\), 发现 \(最多状态数 = 4000*800\), 可做。
设 \(f[i][j][k]\) 表前 \(i\) 个, 选了 \(j\) 个, 差值为 \(k\)。
最多转移总数也是 \(O(4000*800)\) 的。
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
const int M = 25;
const int base = 400;
int n,m,p[N],d[N],sp[N],sd[N];
int f[N][M][805]; // 0为正, 1为负
int pre[N][M][805];
inline void cmax(int &x,int y) {x=max(x,y); }
inline bool ok(int k) {return k>=-400&&k<=400;}
void out(int i,int j,int k,int dd,int pp) {
if(i==0&&j==0&&k==0) {
printf("Best jury has value %d for prosecution and value %d for defence:\n",pp,dd);
return;
}
if(pre[i][j][k+base]) {
out(i-1,j-1,k-(d[i]-p[i]),dd+d[i],pp+p[i]);
printf(" %d", i);
} else {
out(i-1,j,k,dd,pp);
}
}
void sol() {
memset(pre,0,sizeof pre);
memset(f,-0x3f,sizeof f);
f[0][0][0+base]=0;
int ansi,ansj,ansk=10000,ansv=-1;
for(int i=1;i<=n;++i) {
for(int j=0;j<=min(i,m);++j) {
for(int k=-400;k<=400;++k) {
f[i][j][k+base] = f[i-1][j][k+base];
pre[i][j][k+base] = 0;
int prek = k-(d[i]-p[i]);
if(j>0 && ok(prek) && f[i-1][j-1][prek+base]+(d[i]+p[i])>f[i][j][k+base]) {
f[i][j][k+base] = f[i-1][j-1][prek+base]+(d[i]+p[i]);
pre[i][j][k+base] = 1;
// cmax(f[i][j][k+base], f[i-1][j-1][prek+base]+(d[i]+p[i]));
}
if(j==m&&f[i][j][k+base]>=0) //cout<<k<<‘ ‘<<f[i][j][k+base]<<‘\n‘;
{
if(abs(k)<abs(ansk)) {
ansv=f[i][j][k+base];
ansi=i,ansj=j,ansk=k;
}
else if(abs(k)==abs(ansk) && f[i][j][k+base]>ansv) {
ansv=f[i][j][k+base];
ansi=i,ansj=j,ansk=k;
}
}
}
}
}
out(ansi,ansj,ansk,0,0);
cout<<"\n\n";
}
int main()
{
int id = 0;
while(scanf("%d%d", &n,&m)==2 && n && m) {
for(int i=1;i<=n;++i) { scanf("%d%d",&p[i],&d[i]);
sp[i]=sp[i-1]+p[i], sd[i]=sd[i-1]+d[i];
}
printf("Jury #%d\n", ++id);
sol();
}
return 0;
}
先随便求一个点的最大流,然后换根。
有点细节。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+15;
int n, deg[N];
int ct,hd[N],nt[N<<1],vr[N<<1],vl[N<<1];
void ad(int u,int v,int w) {
vr[++ct]=v, vl[ct]=w, nt[ct]=hd[u], hd[u]=ct;
}
int f[N];
void dfs(int x,int fa) {
f[x]=0;
for(int i=hd[x];i;i=nt[i]) {int y=vr[i]; if(y==fa)continue;
dfs(y,x);
if(deg[y]==1&&y!=1) f[x] += vl[i];
else f[x] += min(f[y], vl[i]);
}
}
void getans(int x,int fa) {
for(int i=hd[x];i;i=nt[i]) {int y=vr[i]; if(y==fa)continue;
if(deg[x]==1) f[y] = f[y] + vl[i];
else f[y] = f[y] + min(vl[i], f[x]-min(vl[i],f[y]));
getans(y,x);
}
}
int main()
{
int T;cin>>T;while(T--) {
scanf("%d",&n);
ct=0;
memset(deg,0,sizeof deg);
memset(hd,0,sizeof hd);
for(int i=1;i<n;++i) { int u,v,w;
scanf("%d%d%d", &u,&v,&w); ad(u,v,w); ad(v,u,w);
++deg[u], ++deg[v];
}
dfs(1,0);
getans(1,0);
for(int i=2;i<=n;++i) f[i]=max(f[i],f[i-1]);
cout<<f[n]<<‘\n‘;
}
return 0;
}
码农题。
暴力:
\(f[i][k][l][r][0/1][0/1]\) 表示前 \(i\) 行选了 \(k\) 个, 第 \(i\) 行选了 \([l,r]\), 左右边界状态分别是 \(\{递增(1),递减(0)\}\) 之一时的最大权。
总状态数 \(1518750*2\), 加上转移要枚举 \(O(341718750*2)\) 次, 很难受。
\(\text{Rep(i,1,n);}\) 保平安。
#include<bits/stdc++.h>
using namespace std;
const int N = 16;
const int inf = 2100000000;
#define Rep(i,l,r) for(int i=(l);i<=(r);++i)
int n,m,k,sc[N][N],ssc[N][N];
int f[N][226][N][N][2][2];
int _pi[N][226][N][N][2][2], _pj[N][226][N][N][2][2], _pl[N][226][N][N][2][2];
int _pr[N][226][N][N][2][2], _px[N][226][N][N][2][2], _py[N][226][N][N][2][2];
inline void ud(int i,int j,int l,int r,int x,int y, int ii,int jj,int ll,int rr,int xx,int yy) {
_pi[i][j][l][r][x][y] = ii;
_pj[i][j][l][r][x][y] = jj;
_pl[i][j][l][r][x][y] = ll;
_pr[i][j][l][r][x][y] = rr;
_px[i][j][l][r][x][y] = xx;
_py[i][j][l][r][x][y] = yy;
}
int cost(int i,int l,int r) {return ssc[i][r]-ssc[i][l-1]; }
int ans,ansi,ansj,ansl,ansr,ansx,ansy;
bool vis[N][N];
void tag(int i,int j,int l,int r,int x,int y) {
if(j==0) return;
Rep(I,l,r) vis[i][I] = 1;
tag(_pi[i][j][l][r][x][y], _pj[i][j][l][r][x][y], _pl[i][j][l][r][x][y],
_pr[i][j][l][r][x][y], _px[i][j][l][r][x][y], _py[i][j][l][r][x][y]);
}
int main() {
scanf("%d%d%d",&n,&m,&k);
Rep(i,1,n)Rep(j,1,m) {scanf("%d", &sc[i][j]); ssc[i][j]=sc[i][j]+ssc[i][j-1]; }
Rep(i,0,n)Rep(j,1,k)Rep(l,1,m)Rep(r,l,m)Rep(x1,0,1)Rep(y1,0,1) f[i][j][l][r][x1][y1] = -inf;
Rep(i,0,n)Rep(l,1,m)Rep(r,l,m)Rep(x1,0,1)Rep(y1,0,1) f[i][0][l][r][x1][y1] = 0;
Rep(i,1,n)Rep(j,1,k)Rep(l,1,m)Rep(r,l,m) {
if(j<r-l+1) continue;
//x=0递增 y=0递增
//由x=0/1, y=0 转移来
Rep(pl,1,l)Rep(pr,l,r) {
int &now = f[i][j][l][r][0][0];
Rep(x1,0,1) if(now<f[i-1][j-(r-l+1)][pl][pr][x1][0]+cost(i,l,r)) {
now = f[i-1][j-(r-l+1)][pl][pr][x1][0]+cost(i,l,r);
ud(i,j,l,r,0,0, i-1,j-(r-l+1),pl,pr,x1,0);
}
}
//x=0递增 y=1递减
//由x=0/1, y=0/1 转移来
Rep(pl,1,l)Rep(pr,r,m) {
int &now = f[i][j][l][r][0][1];
Rep(x1,0,1)Rep(y1,0,1) if(now<f[i-1][j-(r-l+1)][pl][pr][x1][y1]+cost(i,l,r)) {
now = f[i-1][j-(r-l+1)][pl][pr][x1][y1]+cost(i,l,r);
ud(i,j,l,r,0,1, i-1,j-(r-l+1),pl,pr,x1,y1);
}
}
//x=1递减 y=0递增
//由x=1 y=0 转移来
Rep(pl,l,r)Rep(pr,pl,r) {
int &now = f[i][j][l][r][1][0];
if(now<f[i-1][j-(r-l+1)][pl][pr][1][0]+cost(i,l,r)) {
now = f[i-1][j-(r-l+1)][pl][pr][1][0]+cost(i,l,r);
ud(i,j,l,r,1,0, i-1,j-(r-l+1),pl,pr,1,0);
}
}
//x=1递减 y=1递减
//由x=1 y=0/1转移来
Rep(pl,l,r)Rep(pr,r,m) {
int &now = f[i][j][l][r][1][1];
Rep(y1,0,1) if(now<f[i-1][j-(r-l+1)][pl][pr][1][y1]+cost(i,l,r)) {
now = f[i-1][j-(r-l+1)][pl][pr][1][y1]+cost(i,l,r);
ud(i,j,l,r,1,1, i-1,j-(r-l+1),pl,pr,1,y1);
}
}
if(j==k) {
Rep(x1,0,1)Rep(y1,0,1) if(ans<f[i][j][l][r][x1][y1]) {
ans = f[i][j][l][r][x1][y1];
ansi=i, ansj=j, ansl=l, ansr=r, ansx=x1, ansy=y1;
}
}
}
printf("Oil : %d\n", ans);
tag(ansi,ansj,ansl,ansr,ansx,ansy);
Rep(i,1,n)Rep(j,1,m) if(vis[i][j]) printf("%d %d\n",i,j);
return 0;
}
标签:单调队列 containe com rac ble name des 暴力 位置
原文地址:https://www.cnblogs.com/tztqwq/p/13198717.html