[CF71E]Nuclear Fusion
题目
题解
这个原子序数是真的狗
首先,看一下那可怜的数据范围:\(1\le k\le n\le 17\),那么小?考虑直接暴力...
考虑定义暴力函数 dfs(const int now,const int s)
为我们已经处理到目标原子 \(now\),而剩下的元素情况为 \(s\) 的局面,显然 \(s\) 是一个小雨等于 \(2^{17}\) 的二进制串,显然,我们选择的组成 \(now\) 的原子一定是 \(s\) 的子集,可以这样枚举子集:
for(int t=s;t;t=(t-1)&s)
在这些子集中,找一个子集使得他们的和刚好为 \(b[now]\) 的值,最后如果 \(now=k+1\) 并且 \(s=0\) 时,找到合法解并直接输出。
为了降低复杂度,我们可以定义一个记忆化数组 bool failed[]
表示 dfs(now,s)
是否失败过,如果曾经失败过就不用再找了
状态有 \(17\times 2^{17}\),子集的枚举是 \(2^{17}\),极限复杂度似乎为 \(\mathcal O(17\times 2^{17}\times 2^{17})\),但是由于我们每一次枚举子集,都只会把 \(1\) 变成 \(0\),而 \(0\) 再也变不回 \(1\),所以之多只有 \(17\) 层,时间复杂度为 \(\mathcal O(17\times 17\times 2^{17})=\mathcal O(37879808)\)
代码
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
typedef long long LL;
// typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned uint;
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void read(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T read(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=17;
const int MAXSIZE=(1<<MAXN)-1;
const string atom[]={"","H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca","Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd","Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th","Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"};
map<string,int>val;
string ori[MAXN+5],goal[MAXN+5];
int a[MAXN+5],b[MAXN+5],n,k,all;
int sum[MAXSIZE+5];
inline void Init(){
rep(i,1,100)val[atom[i]]=i;
cin>>n>>k;
rep(i,0,n-1){
cin>>ori[i];
a[i]=val[ori[i]];
}
// cout<<"this is ori:"<<endl;
// rep(i,0,n-1)cout<<ori[i]<<' '<<a[i]<<endl;
rep(i,0,k-1){
cin>>goal[i];
b[i]=val[goal[i]];
}
// cout<<"this is goal:"<<endl;
// rep(i,0,n-1)cout<<goal[i]<<' '<<b[i]<<endl;
}
inline void Make_sum(){
all=(1<<n)-1;
rep(t,0,all)rep(i,0,n-1)if((t>>i)&1)sum[t]+=a[i];
// rep(i,0,all)printf("sum[%d] == %d\n",i,sum[i]);
}
int situ[MAXN+5];
bool failed[MAXN+5][MAXSIZE+5];
bool Dfs(const int now,const int s){
// printf("Dfs:>now == %d, s == %d\n",now,s);
if(now==k){//注意 : 我们是从 0 开始存的
if(s==0)return true;
return false;
}
if(sum[s]<b[now])return false;
if(failed[now][s])return false;
for(int t=s;t;t=s&(t-1))if(sum[t]==b[now]){
situ[now]=t;
if(Dfs(now+1,s^t))return true;
}
failed[now][s]=true;
return false;
}
inline void WritAns(const bool exist){
if(!exist)return void(cout<<"NO"<<endl);
cout<<"YES"<<endl;
rep(t,0,k-1){
rep(i,0,n-1)if((situ[t]>>i)&1){
cout<<ori[i];
situ[t]^=(1<<i);
if(situ[t])cout<<"+";
else{cout<<"->";break;}
}cout<<goal[t]<<endl;
}
}
signed main(){
Init();
Make_sum();
if(Dfs(0,all))WritAns(true);
else WritAns(false);
return 0;
}