[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;
}
上一篇:算法训练 Anagrams问题


下一篇:物理专业英语词汇(H-N)