DP2

找不到什么分类,乱炖就是了。

P10971 Cookies

\(g_i\) 从小到大排序,设 \(a_i\) 为 第 \(i\) 个人分到的糖果数,则应有 \(a_{i}\le a_{i+1}\)

按层考虑,每次我们会选择一段后缀保留,并这段人每人分配一个糖果,因此 \(f_{i,j}\) 表示还剩 \(i\) 个小朋友存活,已经分了 \(j\) 个糖果,枚举下一轮存活的小朋友数 \(k\),有 \(k\le j,i+k\le m\),然后 \(f_{i,j}+k\sum_{l=n-j+1}^{n-k}g_l\to f_{i+k,k}\),因为这一轮去世的小朋友都会比后面的小。

输出方案的话记录一下来源即可。

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=33,M=5003;
const ll F=1e18;
int n,m,s[N];
pair<int,int> a[N];
int g[N][M],sum[N];
ll f[N][M],ans=F;
void calc(int x,int y){
    if(y==0)return;
    for(int i=n;i>=n-x+1;--i)
        ++sum[a[i].second];
    int tx=g[x][y]/M,ty=g[x][y]%M;
    calc(tx,ty);
}signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        cin>>a[i].first,a[i].second=i;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i)
        s[i]=s[i-1]+a[i].first;
    for(int i=0;i<N;++i)
        for(int j=0;j<M;++j)
            f[i][j]=F;
    f[n][n]=0;
    for(int i=n;i<m;++i){
        for(int j=n;j>=1;--j){
            for(int k=1;k<=j;++k){
                if(i+k<=m){
                    ll tmp=f[j][i]+1ll*k*(s[n-k]-s[n-j]);
                    if(tmp<f[k][i+k])
                        f[k][i+k]=tmp,g[k][i+k]=j*M+i;
                }
            }
        }
    }
    for(int i=1;i<=n;++i)
        ans=min(ans,f[i][m]);
    cout<<ans<<'\n';
    for(int i=1;i<=n;++i){
        if(ans!=f[i][m])continue;
        calc(i,m);
        for(int j=1;j<=n;++j)
            cout<<sum[j]<<' ';
        cout<<'\n';
        break;
    }
    return 0;
}

P14309 【MX-S8-T2】配对

先考虑偶数。

\(s_u\) 表示 \(u\) 子树内 \(c_i\) 的异或和。若 \(c_u=1\)\((u,fa_u)\) 这条边要算上。然后交换操作就是选择一条 \(c_u=0,c_v=1\) 的路径将这条路径所有点 \(s_i\) 取反。直接 dp,\(f_{u,0/1/2/3}\) 表示 \(u\) 的子树内选了 \(c_v=0\)\(v\to u\) 的链、\(c_v=1\)\(v\to u\) 的链、没有选链、子树内已经将链拼完的最小值。

奇数时相当于还要选一条 \(c_u=1\)\(root\) 的路径将路径 \(s_i\) 取反,再加一维 \(0/1\) 即可表示是否有选即可。

赛事思路凌乱,写的比较暴力。

赛时代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5;
int n,c[N],s[N],sc;
int head[N],tot;
ll f[N][4][2],g[4][2];
struct edge{int v,w,nxt;}e[N<<1];
void add(int u,int v,int w){
	e[++tot]=(edge){v,w,head[u]},head[u]=tot;
	e[++tot]=(edge){u,w,head[v]},head[v]=tot;
}ll min(ll x,ll y,ll z,ll w){
	return min(min(x,y),min(z,w));
}ll min(ll a,ll b,ll c,ll d,ll e,ll f,ll g,ll h){
	return min(min(a,b,c,d),min(e,f,g,h));
}void dfs(int u,int fa){
	f[u][2][0]=f[u][s[u]=c[u]][0]=0;
	if(c[u])f[u][2][1]=f[u][1][1]=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].v,w=e[i].w;
		if(v==fa)continue;
		dfs(v,u),s[u]^=s[v];
		int x=s[v]*w,y=(s[v]^1)*w;
		for(int j=0;j<4;++j)
			g[j][0]=f[u][j][0],g[j][1]=f[u][j][1];
        f[u][2][0]=    g[2][0]+f[v][2][0]+x;
		f[u][2][1]=min(g[2][0]+f[v][2][1]+y,g[2][1]+f[v][2][0]+x);
		f[u][1][0]=min(g[2][0]+f[v][1][0]+y,g[1][0]+f[v][2][0]+x);
		f[u][0][0]=min(g[2][0]+f[v][0][0]+y,g[0][0]+f[v][2][0]+x);
		f[u][3][0]=min(g[2][0]+f[v][3][0]+x,g[3][0]+f[v][2][0]+x,
					   g[1][0]+f[v][0][0]+y,g[0][0]+f[v][1][0]+y);
		f[u][1][1]=min(g[2][0]+f[v][1][1]+x,g[1][0]+f[v][2][1]+y,
                       g[1][1]+f[v][2][0]+x,g[2][1]+f[v][1][0]+y);
		f[u][0][1]=min(g[0][1]+f[v][2][0]+x,g[2][1]+f[v][0][0]+y,
					   g[2][0]+f[v][0][1]+x,g[0][0]+f[v][2][1]+y);
		f[u][3][1]=min(g[3][0]+f[v][2][1]+y,g[3][1]+f[v][2][0]+x,
					   g[2][0]+f[v][3][1]+y,g[2][1]+f[v][3][0]+x,
					   g[1][0]+f[v][0][1]+x,g[1][1]+f[v][0][0]+y,
					   g[0][0]+f[v][1][1]+x,g[0][1]+f[v][1][0]+y);
	}
}signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;++i)
		cin>>c[i],sc^=c[i];
	for(int i=1,u,v,w;i<n;++i)
		cin>>u>>v>>w,add(u,v,w);
    for(int i=1;i<=n;++i)
		for(int j=0;j<4;++j)
			f[i][j][0]=f[i][j][1]=1e18;
	dfs(1,0),cout<<f[1][3][sc]<<'\n';
	return 0;
}
posted @ 2025-10-28 21:10  zzy0618  阅读(6)  评论(0)    收藏  举报