Codeforces - 71E 状压DP

参考官方题解

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
using namespace std;
string s[100]={"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"};
int num[111],ans[111][111],vec[111],que[111],p[1<<18|1];
int dp1[1<<18|1],dp2[1<<18|1];
int n,k,sum1,sum2;
string str;
bool go(){
    memset(dp1,0,sizeof dp1);
    memset(dp2,0,sizeof dp2);
//  memset(dp2,-1,sizeof dp2);
    rep(S,1,(1<<n)-1){
        rep(i,1,n){
            if((S>>(i-1))&1){
                dp1[S]+=vec[i];
            }
        }
    }
    rep(S,1,(1<<n)-1){
        dp2[S]=-1;
        for(int S0=S;S0;S0=(S0-1)&S){
            if(dp2[S^S0]!=-1&&que[dp2[S^S0]+1]==dp1[S0]){
                dp2[S]=dp2[S^S0]+1;
                p[S]=S^S0;
            }
        }
    }
    if(dp2[(1<<n)-1]!=k) return 0;
    int x=(1<<n)-1;
    rrep(i,k,1){
        rep(j,1,n){
            if(1<<(j-1)&(x^p[x])){
                ans[i][++num[i]]=j;
            }
        }
        x=p[x];
    }
    return 1;
}
inline void print(){
    cout<<"YES"<<endl;
    rep(i,1,k){
        cout<<s[vec[ans[i][1]]-1];
        rep(j,2,num[i]){
            cout<<"+"<<s[vec[ans[i][j]]-1];
        }
        cout<<"->"<<s[que[i]-1]<<endl;
    }
}
int main(){
    while(cin>>n>>k){
        sum1=sum2=0;
        memset(num,0,sizeof num);
        rep(i,1,n){
            cin>>str;
            rep(j,0,100-1){
                if(str==s[j]){
                    vec[i]=j+1;
                    sum1+=j+1;
                    break;
                }
            }
        }
        rep(i,1,k){
            cin>>str;
            rep(j,0,100-1){
                if(str==s[j]){
                    que[i]=j+1;
                    sum2+=j+1;
                    break;
                }
            }
        }
        if(sum1==sum2&&go()) print();
        else cout<<"NO"<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/caturra/p/8456545.html

时间: 2024-08-29 18:45:25

Codeforces - 71E 状压DP的相关文章

codeforces 580d 状压DP

题意:有n种菜,现在选m种菜来吃,如果在吃y的前一道菜是x的话,那么就可以获得额外满意度.每一种菜都有一个满意度. 思路:设dp[i][S]表示为最后一道菜为i,现在的菜吃的状态为S.S中的二进位如果为1表示已经吃了,如果是0则表示没吃,状压DP,答案就出了. #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm>

Codeforces 8C 状压DP

题意:有个人想收拾行李,而n个物品散落在房间的各个角落里(n < 24).现在给你旅行箱的坐标(人初始在旅行箱处),以及n个物品的坐标,你一次只能拿最多两个物品,并且拿了物品就必须放回旅行箱,不能暂时放在地上.问最小的花费是多少?花费是笛卡尔距离的平方. 思路一看n 只有24,应该很容易想到要用状压DP. 那么dp[i]表示i状态并且回到原点的最小花费.那么就暴力枚举拿1个或两个物品放回原点,然后转移就行了.需注意,这个题目中拿物品的顺序对答案无影响,比如先拿1号,再拿2号和先拿2号,再拿1号的

codeforces 1185G1 状压dp

include include include include include include include include include include include include include include include using namespace std; typedef long long LL; typedef long long ll; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typed

2017-03-18 HDU 5733 计算几何 codeforces 599E 状压dp(待补)

HDU 5733 题意:给出四面体的四个顶点,求出其内切球的球心坐标和半径,如果不存在内切球,输出"O O O O". tags:一堆公式..可以做模板了 我们可以将平面上的四点得到由同一个点出发的三个矢量.这样就可以计算这三个矢量的混合积M,则M/6即为四面体体积V. 题目无解的情况当且仅当四点共面,即混合积为0. 求得四面体体积后,可以根据公式r = 3V/(S1+S2+S3+S4)得到内切球半径, S1~S4为四面体四个面的面积. 当前的问题转化为如何求四面体四个面的面积. 由于

Codeforces Gym 100676G Training Camp 状压dp

http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修该课程必须修完先修课程.问最多能学到多少点数. 非常简单的一道状压dp(一开始我还误导队友写成两维的去了 T^T); dp[s] : s 的二进制存放的是已经选择的课程,在该状态下的能获得的最大的点数. 这时如果再学一门课程k,将转移到状态ss (s | (1 << k) ) ,能否转移需要判断合

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

Codeforces 580D-Kefa and Dishes(状压DP)

原题链接:http://codeforces.com/problemset/problem/580/D 题意:在n个数字中有顺序地选择m个数字,每个数字对应有个值ai,每取一个数字答案加上ai,并且存在k个关系:x y c,如果x恰好排在y的前面,那么答案再加上ci的值.输出最大值. 思路:状压dp.dp[i][j]中,i是已经选了若干个数的情况,j是最后一个被选取的数,i从选取1个到m个枚举下去,j从第1个数到第n个数进行枚举就能得到答案. AC代码: 1 #include<iostream>

CodeForces 757D Felicity&#39;s Big Secret Revealed(状压DP)

题意:给定一个01串,一个有效的n切割定义如下:一个横杠代表一次切割,第一条横杠前面的01串不算,最后一条横杠后面的01串不算,将两个横杠中的01串转化成十进制数字,假设这些数字的最大值是MAX且这些数字囊括了1-MAX的所有数字,则称为一次有效切割.求2~n+1次有效切割的切法. 思路: 由于题目要求包含所有1-MAXN的数字,且n<=75,所以MAXN<=20.另dp[i][j]表示第i位前面有一个横杆且存在j这个状态,接着从第i位开始枚举到第j位为下一个横杆的位置,设这两段横杆之间的数字

codeforces 453 B Little Pony and Harmony Chest (状压dp)

题目大意: 需要你构造一个b数组.使得b数组中的所有元素互质. 而且使得b数组与a数组中的每个对应下标元素的差值和最小. 思路分析: 考虑到 a中所有元素都是 0 - 30. 所以b中的元素也只可能在 0 - 59. 因为如果b 选择60的话,结果和1是一样的,而且b序列中 1 可以重复出现很多次. 因为gcd (1,x) = 1.. 所以们首先把2 - 59中的所有素数处理出来,只有17个. 然后状压这些素数因子. dp[i] [s] [0] 表示 递推到第 i 个位置 达到素数因子为s的状态