菌落
最初想法
对题目中要求的不同颜色, 可以通过正负号来区分, 操作时直接相加即可,
设
- F[i,s] 表示前 i 天, 状态为 s 的最小花费, s是一个 0/1串,
- A[i,s,k] 表示前 i 天, 状态为 s, 第 k 个位置的值 .
则 初值: F[0,(1<<N)−1]=0, 其余为 inf .
F[i,s] 能够更新以下状态 ↓
- F[i,s xor (1<<j−1)]=min(F[i−1,s]+cost)
- F[i,s xor (1<<k−1)]=min(F[i−1,s]+cost)
其中 j 与 k 为枚举的 决策, 具体地说, 表示 j 与 k 位置上的数字合并, 且重新放在 j 或者 k 位置上 .
A[] 数组的更新就不在多说了 .
为什么会错啊啊啊啊!!!
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const ll inf = 10000000000000015;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
ll B[12];
ll A[12][1029][12];
ll F[12][1029];
char tmp_s[10];
void Work(){
N = read();
for(reg int i = 1; i <= N; i ++){
B[i] = read();
scanf("%s", tmp_s);
if(tmp_s[0] == '8') B[i] = -B[i];
}
std::reverse(B+1, B+N+1);
for(reg int i = 1; i <= N; i ++) A[0][(1<<N)-1][i] = B[i];
for(reg int i = 0; i <= N; i ++)
for(reg int j = 0; j < 1<<N; j ++) F[i][j] = inf;
F[0][(1<<N)-1] = 0;
srand(19260817);
for(reg int i = 1; i < N; i ++)
for(reg int s = (1<<N)-1; s >= 0; s --){
if(F[i-1][s] == inf) continue ;
for(reg int j = 1; j <= N; j ++){
if(!(s & (1<<j-1))) continue ;
for(reg int k = j+1; k <= N; k ++){
if(k == j || !(s & (1<<k-1))) continue ;
ll &t = F[i][s^(1<<j-1)];
for(reg int p = 1; p <= N; p ++) B[p] = A[i-1][s][p];
B[j] = 0, B[k] = A[i-1][s][j] + A[i-1][s][k];
ll cost = 0;
int zt = s^(1<<j-1);
for(reg int p = 1; p <= N; p ++)
if(zt & (1<<p-1)) cost += 1ll*B[p]*B[p];
ll tmp = F[i-1][s] + cost;
if(t > tmp || (rand()%2 == 0 && t == tmp)){
t = tmp;
for(reg int p = 1; p <= N; p ++) A[i][zt][p] = A[i-1][s][p];
A[i][zt][j] = 0;
A[i][zt][k] = A[i-1][s][j] + A[i-1][s][k];
}
ll &t2 = F[i][s^(1<<k-1)];
if(t2 > tmp || (rand()%2 == 0 && t2 == tmp)){
t2 = tmp;
zt = s^(1<<k-1);
for(reg int p = 1; p <= N; p ++) A[i][zt][p] = A[i-1][s][p];
A[i][zt][k] = 0;
A[i][zt][j] = A[i-1][s][j] + A[i-1][s][k];
}
}
}
}
ll Ans = inf;
for(reg int i = 0; i < N; i ++) Ans = std::min(Ans, F[N-1][1<<i]);
printf("%lld\n", Ans);
}
int main(){
freopen("germ.in", "r", stdin);
freopen("germ.out", "w", stdout);
int T = read();
while(T --) Work();
return 0;
}
正解部分
404 Not Found
实现部分
404 Not Found
#include<bits/stdc++.h>
using namespace std;
int n,t,fac[15],tri[15];
long long a[15],f[3628805],F,d,tp[15];
char s[15];
long long dfs(int x){
if(f[x]!=1e18) return f[x];
int th;
long long dd;
for(int i=0;i<n;i++){
if(tri[i]==0&&i>0) continue;
for(int j=i+1;j<n;j++){
if(tri[j]==0) continue;
int t1=tri[i],t2=tri[j];
long long t3=tp[i],t4=tp[j];
long long ddd=d;
th=x;th-=tri[j]*j+tri[i]*i;
tri[i]=tri[i]+tri[j];
tri[j]=0;th+=tri[i]*i;
d-=tp[i]*tp[i]+tp[j]*tp[j];
tp[i]=tp[i]+tp[j];
tp[j]=0;d+=tp[i]*tp[i];
dd=d;
f[x]=min(f[x],dfs(th)+dd);
tri[i]=t1,tri[j]=t2;
tp[i]=t3,tp[j]=t4;
d=ddd;
}
}
return f[x];
}
int main(){
freopen("germ.in","r",stdin);
freopen("germ.out","w",stdout);
scanf("%d",&t);
fac[0]=1;
for(int i=1;i<=10;i++) fac[i]=i*fac[i-1];
f[0]=0;
while(t--){
scanf("%d",&n);
F=d=0;
for(int i=1;i<=n;i++){
scanf("%lld %s",&a[i],s+1);
if(s[1]=='8') a[i]=-a[i];
F+=(i-1)*fac[i-1];
tri[i-1]=fac[i-1];
tp[i-1]=a[i];
d+=tp[i-1]*tp[i-1];
}
for(int i=1;i<=3628800;i++) f[i]=1e18;
printf("%lld\n",dfs(F));
}
return 0;
}