专栏文章

AT_abc432_f 题解

AT_abc432_f题解参与者 4已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@min6o5py
此快照首次捕获于
2025/12/01 21:26
3 个月前
此快照最后确认于
2025/12/01 21:26
3 个月前
查看原文
状压 DP。恶心点在于还要还原方案 /tuu 而且码量不小。
显然要先把所有糖果的数量总和算出来,不是 nn 的倍数直接无解。否则算出平均值。
首先我们会发现一个特别,啊,显然的性质,就是一次糖果的传递,比如说 xxyy 多少颗糖,经过这次操作后 xxyy 这两个人之中一定有一个人已经到达了平均值,不排除两人都到的情况。
这个性质可以延伸出另一个性质,那就是说,一颗糖果绝对不会经过一个人的交手。这样说是不是很模糊啊,那我换种方式,就是说一个糖果最多只会拥有过两个主人,不会说 xx 给了 yyyy 又给了 zz,那何必呢,直接让 xxzz 不就得了。
所以根据这些性质,如果你当前只考虑了一部分的人,这之中必定最多只有一个人糖果数还没达标。
于是这样就可以定义状态,dpst,idp_{st,i} 表示当前考虑了 stst 这个二进制压缩集合中的人的糖果情况,且还有 ii 这位虽然经过过操作但是糖果数还没达标的人。当然了也有全部达标的情况,这个时候我们就让 ii 这一位表示成 00,也就是目前考虑过的人中没有人的糖果数还没达标啦!
最终答案就是 dp2n1,0dp_{2^n-1,0}
初始时肯定全赋初值为 \infty。找最初就糖果数达标的作为起始 strtstrt,让 dpstrt,0=0dp_{strt,0} = 0,这就是初值。
接下来考虑转移。
首先枚举 stst,特殊转移第二维是 00 的情况——枚举 ii,只要 dpst,i>dpst,0dp_{st,i} > dp_{st,0},就可以转移 dpst,i=dpst,0dp_{st,i} = dp_{st,0},顺便记录路径方便后面找方案。
接下来枚举 DP 的第二维 ii,这里用的是扩散型,对,上面用的也是扩散型。再枚举一个 jj,要新加一个 jj 进来,当然 jj 一定不能在 stst 中或者等于 ii。并且还有一点很重要的,你会算出 DiDiDjDj 两个标识符,表示 iijj 这两个人距离糖果数达标还需要多少。你必须保证 DiDiDjDj 的正负号是不一样的——不然你很有可能给不起!
之后就是判断了,要是 DiDiDjDj 正好相互补上,就能弄出 DP 转移第二维是 00 的情况,stst 就会加上 iijj 两个人;如果 DiDi 的绝对值更小一些,就考虑让 ii 达标,让 jj 去成全 ii,把 ii 包含进 stst 并让第二维是 jj;反之如果 DjDj 的绝对值更小一些,久石让 jj 达标,让 ii 成全 jj,把 jj 包含到 stst 里头,第二维还是 ii。在这个转移的过程中,要记得及时记录路径,以及要判断这种转移优不优,别越弄越劣了就行。
这样转移环节就结束了,思维难度不高,但是由于有多种情况,代码还有点儿长。
最后输出答案即可,额外再跑一个 DFS 倒着回来找方案,后序遍历顺序输出方案的具体情况即可。
于是这题就搞完啦!有些小细节需要注意一下,本人补题时调了将近一个小时。
CPP
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
using namespace std;
const int N = (1<<20)+5;
const int Inf = 0x3f3f3f3f;
struct node{int x,y,z;}g[N][30];
int n,a[30],s[N],c[N],sum,strt,dp[N][30];
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
void DFS_rtans(int x,int y){
    if(x==strt&&y==0)return;
    if(x==-1||y==-1)return;
    auto [p,q,o]=g[x][y];
    if(p==0)DFS_rtans(x,0);
    else{
        if(y==0)DFS_rtans((x^(1<<p-1)^(1<<q-1)),p);
        else if(y==q)DFS_rtans(x^(1<<p-1),p);
        else DFS_rtans(x^(1<<q-1),p);
        if(o>0)cout<<p<<" "<<q<<" "<<o<<"\n";
        else cout<<q<<" "<<p<<" "<<-o<<"\n";
    }return;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),sum+=a[i];
    if(sum%n!=0){cout<<"-1\n";return 0;}sum/=n;
    for(int st=0;st<(1<<n);st++)
        for(int i=1;i<=n;i++)
            if((st>>i-1)&1)s[st]+=a[i],c[st]++;
    for(int i=1;i<=n;i++)
        if(a[i]==sum)strt|=(1<<i-1);
    memset(dp,0x3f,sizeof(dp));dp[strt][0]=0;
    for(int st=0;st<(1<<n);st++)
        for(int i=0;i<=n;i++)g[st][i]={-1,-1,-1};
    for(int st=0;st<(1<<n);st++){
        if(dp[st][0]!=Inf)for(int i=1;i<=n;i++)
            if(!((st>>i-1)&1)&&dp[st][0]<dp[st][i])
                dp[st][i]=dp[st][0],g[st][i].x=0;
        for(int i=1;i<=n;i++){
            if(dp[st][i]==Inf)continue;
            for(int j=1;j<=n;j++){
                int di=s[st|(1<<i-1)]-c[st|(1<<i-1)]*sum;
                int dj=a[j]-sum,ds=min(abs(di),abs(dj));
                if(((st>>j-1)&1)||((di<0)==(dj<0)))continue;
                if(ds==abs(di)&&ds==abs(dj)){
                    if(dp[st][i]+1<dp[st|(1<<i-1)|(1<<j-1)][0])
                        dp[st|(1<<i-1)|(1<<j-1)][0]=dp[st][i]+1,
                        g[st|(1<<i-1)|(1<<j-1)][0]={i,j,di};
                }else if(ds==abs(di)){
                    if(dp[st][i]+1<dp[st|(1<<i-1)][j])
                        dp[st|(1<<i-1)][j]=dp[st][i]+1,
                        g[st|(1<<i-1)][j]={i,j,di};
                }else if(ds==abs(dj)){
                    if(dp[st][i]+1<dp[st|(1<<j-1)][i])
                        dp[st|(1<<j-1)][i]=dp[st][i]+1,
                        g[st|(1<<j-1)][i]={i,j,-dj};
                }else;
            }
        }
    }cout<<dp[(1<<n)-1][0]<<"\n";
    DFS_rtans((1<<n)-1,0);
    return 0;
}
如果本篇题解对你有帮助的话,麻烦你点一个小小的赞,真是太感谢啦!

评论

4 条评论,欢迎与作者交流。

正在加载评论...