【JZOJ 5442】【NOIP2017提高A组冲刺11.1】荒诞

时间:2022-12-17 13:59:18

Description

我的灵魂与我之间的距离如此遥远,而我的存在却如此真实。
——加缪《局外人》
我醒来的时候,发现满天星斗照在我的脸上。田野上的声音一直传到我的耳畔。夜的气味,土地的气味,海盐的气味,使我的两鬓感到清凉。这沉睡的夏夜的奇妙安静,像潮水一般浸透我的全身。这时,长夜将尽,汽笛叫了起来。它宣告有些人踏上旅途,要去一个从此和我无关痛痒的世界。
这时我在想一个问题:我有一个n个点,m条边的无向图,第i个点建立一个旅游站点的费用是c_i。特别地,这张图中的任意两点间不存在节点数超过10的简单路径。
为了把一切都做得完善,为了使我感到不那么孤独,我想要建造一些旅游站点使得每个点要么建立了旅游站点,要么与它有边直接相连的点里至少有一个点建立了旅游站点。我还希望这个建造方案总花费尽量少。
请求出这个花费。

Solution

题目里那个奇怪的条件就是告诉你,这张图生成的dfs树的深度不会超过10,
那么就很自然的想到了状压DP,

设f[i][s]表示做到了第i层,状态为S,S是一个3进制数,0表示没有选但被覆盖到了,1表示选了,2表示没有选且没有被覆盖到,

转移显然,

复杂度:注意,并不是 O(n310) ,也就是 O(20000310) ,仔细算你会发现是 O(n/10311) ,也就是 O(2000311) ,才3.5个亿,卡卡常3S不虚,

复杂度仔细算!!!仔细算!!!仔细算!!!

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)<(w)?(q):(w))
using namespace std;
const int N=200500,INF=2139062143;
int read(int &n)
{
    scanf("%d",&n);
    return n;
}
int n,m,ans;
int co[N],C[N];
bool z[N];
int B[3*N][2],A[N],B0;
int er[20];
int f[15][1772000];
void link(int q,int w)
{
    B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;
    B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q;
}
bool OK(int q,int w)
{
    for(;q;q/=3,w/=3)if(q%3==1&&w%3)return 1;
    return 0;
}
int JA(int q,int w,int n)
{
    fo(i,1,n)if((q/er[i])%3==2&&(w/er[i])%3)q-=2*er[i];
    return q;
}
void dfs(int q,int c)
{
    int t=er[c];
    efo(i,q)if(C[B[i][1]])if((t/er[C[B[i][1]]])%3==0)t+=er[C[B[i][1]]];
    C[q]=c;
    fo(i,0,er[c]-1)if(f[c-1][i]<INF)
    {
        if(OK(i,t))f[c][i]=f[c-1][i];
            else f[c][i+2*er[c]]=f[c-1][i];
        int t1=JA(i,t,c-1)+er[c];
        f[c][t1]=min(f[c][t1],f[c-1][i]+co[q]);
    }
    efo(i,q)if(!C[B[i][1]])
    {
        dfs(B[i][1],c+1);
        fo(j,0,er[c+1]-1)
        {
            f[c][j]=min(f[c+1][j],f[c+1][j+er[c+1]]);
            f[c+1][j]=f[c+1][j+er[c+1]]=f[c+1][j+er[c+1]*2]=INF;
        }
    }
}
int main()
{
    freopen("absurdity.in","r",stdin);
    freopen("absurdity.out","w",stdout);
    int q,w;
    er[1]=1;fo(i,2,15)er[i]=er[i-1]*3;
    read(n),read(m);
    fo(i,1,n)read(co[i]);
    fo(i,1,m)read(q),read(w),link(q,w);
    ans=0;
    memset(f,127,sizeof(f));
    memset(f[0],0,sizeof(f[0]));
    fo(i,1,n)if(!C[i])
    {
        dfs(i,1);
        ans+=min(f[1][0],f[1][1]);
        f[1][0]=f[1][1]=f[1][2]=INF;
    }
    printf("%d\n",ans);
    return 0;
}