简单DP就是图论 !
方程想脑抽了,硬是觉得四维循环的DP顺序不对
于是打算用位置递增的顺序正推枚举状态
每个状态用一个五元组 (s1,s2,s3,s4,f) 表示,前四个表示到目前各种牌用了几张,f 表示最大价值
因为 由 s 1~4 可以确定当前的位置,且前面的出牌顺序不会影响后面的决策,
所以该表示法能够完整表示一个状态,并进行正推
可以在每个位置建一个vector (本处使用邻接表)记录该位置的所有状态
顺序枚举每一个位置,枚举到达该位置的所有状态,并利用类似 bfs 的马蜂更新可到达的状态
因为每个状态只会枚举到一次,所以总复杂度仅与状态总数有关 ,上限为 O( 40 4),可以通过
为了防止状态冗余(多次枚举),将f 改写成记忆化数组
(手多还写了个邻接表空间回收)、
code:
//P1613 #include<bits/stdc++.h> using namespace std; #define LL long long #define uLL unsigned long long #define rint register int #define itn int #define mem(x) memset(x,0,sizeof(x)) inline LL read(){ LL x=0,ff=1;char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')ff=-1;ss=getchar();} while(ss<='9'&&ss>='0'){x=x*10+ss-'0';ss=getchar();} return ff*x; } inline void writee(LL x){ if(x<0){putchar('-');x=-x;} if(x>9)writee(x/10); putchar(x%10+'0'); } inline void write(LL x){writee(x);putchar('\n');} inline int min(int x,int y){return x<y?x:y;} inline int max(int x,int y){return x>y?x:y;} inline void ckmax(int &x,int y){if(y>x)x=y;} const int N=361,M=1e6+10; const LL inf=1e14,mod=998244353; int n,m,q; int a[N],b[5]; int Head[N],Next[M<<1],ver[M<<1][5],f[42][42][42][42],tot=1; int dtop,dsta[M]; int ans=0; void del(int e){ Next[e]=0;for(rint i=1;i<=4;i++)ver[e][i]=0; dsta[++dtop]=e; } int dis(int* s){ int dd=1; for(rint i=1;i<=4;i++)dd+=s[i]*i; return dd; } void Add(int x,int* s,int d){ if(f[s[1]][s[2]][s[3]][s[4]]){ckmax(f[s[1]][s[2]][s[3]][s[4]],d);return;} int p=dtop?dsta[dtop--]:++tot; Next[p]=Head[x];Head[x]=p;f[s[1]][s[2]][s[3]][s[4]]=d; for(rint i=1;i<=4;i++)ver[p][i]=s[i]; } int main(){ //freopen("P1541_2.in","r",stdin); n=read();m=read(); for(rint i=1;i<=n;i++)a[i]=read(); for(rint i=1;i<=m;i++)b[read()]++; int s[5],nxt=0; s[1]=s[2]=s[3]=s[4]=0; Add(1,s,a[1]); for(rint i=1;i<=n;i++){ for(int e=Head[i];e;e=nxt){ for(rint j=1;j<=4;j++)s[j]=ver[e][j]; int k=f[s[1]][s[2]][s[3]][s[4]]; for(rint j=1;j<=4;j++) if(s[j]+1<=b[j]){ s[j]++;Add(dis(s),s,k+a[dis(s)]); s[j]--; } nxt=Next[e];del(e); } }write(f[b[1]][b[2]][b[3]][b[4]]); }

浙公网安备 33010602011771号