CF hello 2018(A~E)
2018-01-14 22:59
344 查看
点此打开
A
代码示例
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(false); ll m,n; cin>>n>>m; if(n>=30){ cout<<m<<endl; } else{ cout<<m%(ll)pow(2,n)<<endl; } return 0; }
B
思路
统计叶子节点,判断每个非叶子节点是否满足条件(有>=3个子节点是叶子)代码示例
#include<bits/stdc++.h> using namespace std; int flag; set<int> xiang;//叶子节点的编号 struct Edge{ int from,to,dist; Edge(int u,int v,int w):from(u),to(v),dist(w){ } }; const int maxn=10000;//结点数 int root;//根节点 vector<Edge> edges;//边的具体信息 vector<int> G[maxn];//边的编号 void addEdge(int u,int v,int w){ edges.push_back(Edge(u,v,w)); edges.push_back(Edge(v,u,w)); int size=edges.size(); G[u].push_back(size-2);//从u起点的边在edges中的下标 G[v].push_back(size-1);//从v起点的边在edges中的下标 } void dfs(int n,int fa) { if(G .size()==1&&n!=1){//只有一条边,并且不是根节点 xiang.insert(n); return ; } for(int i=0;i<G .size();++i){ Edge e=edges[G [i]]; if(e.to!=fa){ dfs(e.to,n); } } } void dfs1(int n,int fa) { //cout<<"现在节点为"<<n<<' '<<"父亲为"<<fa<<endl; if(G .size()==1&&n!=1){ return ; } int num=0; for(int i=0;i<G .size();++i){ Edge e=edges[G [i]]; if(e.to!=fa){ if(xiang.count(e.to)) num++; else dfs1(e.to,n); } } if(num<3){ flag=0; return ; } } int main() { flag=1;//默认是杉树 ios::sync_with_stdio(false); root=1;//根节点为1 int n,temp;//结点数 cin>>n; for(int i=2;i<=n;++i){ cin>>temp; addEdge(temp,i,1);//距离这题用不到,置为1 } dfs(root,0);//统计叶子结点 /*输出叶子节点 for(set<int>::iterator it=xiang.begin();it!=xiang.end();++it){ cout<<*it<<' '; } */ dfs1(root,0); if(flag) cout<<"Yes"<<endl; else cout<<"No"<<endl; return 0; }
C
思路
贪心,具体见注释代码示例(WA)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const double eps=1e-6; struct point{ ll vol;//容量 ll pri;//价格 double ahu;//单价 }po[40]; cmp(point a,point b){ if(fabs(a.ahu-b.ahu)<eps) return a.vol<b.vol; else return a.ahu<b.ahu; } int main() { ios::sync_with_stdio(false); //cout<<(ll)pow(2,29)<<endl; ll L;//L为需要的量 //现在提供的升数均为2的次幂 int n;//n种规格 cin>>n>>L; ll ans=0; for(int i=1;i<=n;++i){ po[i].vol=(ll)pow(2,i-1); cin>>po[i].pri; po[i].ahu=po[i].pri*1.0/po[i].vol; } /* for(int i=1;i<=n;++i){ cout<<"第"<<i<<"种瓶子:"<<"容量为"<<po[i].vol<<" 价格为"<<po[i].pri<<" 单价为" 4000 <<po[i].ahu<<endl; } cout<<endl<<endl; */ sort(po+1,po+n+1,cmp); /* for(int i=1;i<=n;++i){ cout<<"第"<<i<<"种瓶子:"<<"容量为"<<po[i].vol<<" 价格为"<<po[i].pri<<" 单价为"<<po[i].ahu<<endl; } */ while(1) { ans+=L/po[1].vol*po[1].pri;//花费的钱 L=L-L/po[1].vol*po[1].vol;//需要买的瓶数 if(L<=0) break; //现在单价最小的被我买完了,说明我剩下的升数是小于这一瓶的升数的 //下面我修改这瓶的单价重新排序 po[1].vol=L; po[1].ahu=po[1].pri*1.0/po[1].vol; sort(po+1,po+n+1,cmp); } cout<<ans<<endl; return 0; }
代码示例(AC)
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { int n,L; scanf("%d %d",&n,&L); vector<int> c(n); for(int i=0;i<n;i++){ scanf("%d",&c[i]); } for(int i=0;i<n-1;i++){//第一步处理,容量加倍但价格加了不止两倍的进行“降价” c[i+1]=min(c[i+1],2*c[i]); } long long ans=(long long) 5e18;//一个较大数 long long sum=0; //从大的开始选 对当前品种最后一个容量(选了会>=L的)做个选择:选还是不选,求出min。选了则买够了,即sum+(L>0)*c[i];没选则继续循环,在当前sum的基础上,还剩下L-=need<<i待够,然后做同样的事情。 //注意:由于瓶子的容量是1,2,4,8...,所以可以保证恰好组成第一次的那个L-=need<<i。所以该题本质就是从一个瓶(这个瓶肯定相比较来说a(i+1)<2*ai ,即更实惠)买够容量,剩下的都不看了。代码所做的就是枚举这个"lucky bottle" for(int i=n-1;i>=0;i--){ int need=L/(1<<i); sum+=(long long)need*c[i]; L-=need<<i; ans=min(ans,sum+(L>0)*c[i]); } cout<<ans<<endl; return 0; }
D
思路
贪心+优先队列维护先对所有的exam按照时间进行排序,时间小的优先。
优先队列 维护数据,limit小的在前面 ;limit一样的 t大的在前面
大致步骤:
①对于每个exam,优先选择时间小的,其时间大于剩余总时间了,break;
②没break,则其可不可选要看其limit是否大于当前已做的ans ,若大于进优先队列,ans++;
③每一次ans改变后,检查优先队列top是否满足限制了,不满足pop,为后面的exam提供选择的可能(ans变小,T变大) 转①
代码示例
//结构体版 #include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; struct point{ int t,limit,id; }pt[maxn]; bool comp(point a,point b){ return a.t<b.t; } struct cmp{//运算符重载 // limit小的在前面 ;limit一样的 t大的在前面 bool operator()(const point &a,const point &b){ if(a.limit==b.limit) return a.t<b.t; return a.limit>b.limit; } }; priority_queue<point,vector<point>,cmp> que; int main() { ios::sync_with_stdio(false); int n,T,ans; ans=0; cin>>n>>T; for(int i=0;i<n;++i){ cin>>pt[i].limit>>pt[i].t; pt[i].id=i+1; } sort(pt,pt+n,comp);//所需时间少的exam排在前面 for(int i=0;i<n;++i){ if(pt[i].t>T) break;//后面的时间铁定不行啦 if(pt[i].limit>ans){//现在还行 T-=pt[i].t; que.push(pt[i]); ans++; } while(!que.empty()&&que.top().limit<ans){//之前进去的可能不行啦 由于是优先队列 //重载的是limit小的在前面 ;limit一样的 t大的在前面 //所以先检验top的limit符不符合 ans--; T+=que.top().t; que.pop(); } } cout<<ans<<endl<<ans<<endl; while(!que.empty()){ cout<<que.top().id<<' '; que.pop(); } return 0; }
E
思路
核心思想:数值取非、相与、相或对应表达式取非、相与、相或另外就是“最短路”松弛思想更新最优解
细节见代码注释
代码示例
#include<bits/stdc++.h> using namespace std; char str[20]; int p;//是否继续“松弛”标志 string dp[256][3];//0表示非状态 1表示与状态 2表示或状态 void orz(string &a,string b)//判断是否更新a,若更新置p为1 { if(b.size()<a.size()||b.size()==a.size()&&b<a) { a=b; p=1; } } int main() { for(int i=0;i<256;++i) for(int j=0;j<3;++j) for(int k=0;k<50;++k){ dp[i][j]+="x"; } dp[15][0]="x";//00001111 对应expression为x dp[51][0]="y";//00110011 对应expression为y dp[85][0]="z";//01010101 对应expression为z p=1; while(p)//注意先对“非”做更新 再对“与” 最后对“或” { p=0;//置0 若下面还有置1的操作则继续循环 直到p一直为0(无松弛的可能性) for(int i=0;i<256;++i){ orz(dp[i][0],"!"+dp[i^255][0]);//异或取反 则逻辑值也相反 因此+! orz(dp[i][0],"!("+dp[i^255][1]+")"); orz(dp[i][0],"!("+dp[i^255][2]+")"); } for(int i=0;i<256;++i){ for(int j=0;j<256;++j){//3*3 9种情况 orz(dp[i&j][1],dp[i][0]+"&"+dp[j][0]);//枚举所有的i,j得到i&j,数值的与等价于表达式的与 orz(dp[i&j][1],dp[i][0]+"&"+dp[j][1]); orz(dp[i&j][1],dp[i][0]+"&("+dp[j][2]+")"); orz(dp[i&j][1],dp[i][1]+"&"+dp[j][0]); orz(dp[i&j][1],dp[i][1]+"&"+dp[j][1]); orz(dp[i&j][1],dp[i][1]+"&("+dp[j][2]+")"); orz(dp[i&j][1],"("+dp[i][2]+")&"+dp[j][0]);//注意与的优先级高于或,因此要加括号 orz(dp[i&j][1],"("+dp[i][2]+")&"+dp[j][1]); orz(dp[i&j][1],"("+dp[i][2]+")&("+dp[j][2]+")"); } } for(int i=0;i<256;++i){ for(int j=0;j<256;++j){//3*3 9种情况 orz(dp[i|j][2],dp[i][0]+"|"+dp[j][0]);//枚举所有的i,j得到i&j,数值的与等价于表达式的与 orz(dp[i|j][2],dp[i][0]+"|"+dp[j][1]); orz(dp[i|j][2],dp[i][0]+"|"+dp[j][2]); orz fcef (dp[i|j][2],dp[i][1]+"|"+dp[j][0]); orz(dp[i|j][2],dp[i][1]+"|"+dp[j][1]); orz(dp[i|j][2],dp[i][1]+"|"+dp[j][2]); orz(dp[i|j][2],dp[i][2]+"|"+dp[j][0]); orz(dp[i|j][2],dp[i][2]+"|"+dp[j][1]); orz(dp[i|j][2],dp[i][2]+"|"+dp[j][2]); } } } int n; cin>>n; for(int i=0;i<n;++i){ cin>>str; int k=0; for(int j=0;j<8;++j){ k=k*2+(str[j]-'0');//转二进制 } string ans=dp[k][0];//选取最优的表达式。当然他们的逻辑值相同,只是长短或者字典序不同 orz(ans,dp[k][1]); orz(ans,dp[k][2]); cout<<ans<<endl; } return 0; }
题解solution1
#include <iostream> #include <set> #include <vector> #include <string> using namespace std; bool ls(const string& a, const string& b) { if (a.length() == b.length()) return a < b; return a.length() < b.length(); } struct Expression { int p, t; string e; Expression(string _e, int t_, int _p) : e(_e), t(t_), p(_p) {} bool operator < (const Expression& ex) const { if (ex.e == e) { if (t != ex.t) { return t < ex.t; } return p < ex.p; } return ls(e, ex.e); } }; set<Expression> q; const int FULL = 0xff; const vector<int> B = {1, 2, 4, 8, 16, 32, 64, 128}; const int X_TABLE = B[4] + B[5] + B[6] + B[7]; const int Y_TABLE = B[2] + B[3] + B[6] + B[7]; const int Z_TABLE = B[1] + B[3] + B[5] + B[7]; string dp[1 << 8][3]; void add(int pr, const string& s, int mask) { if (dp[mask][pr].empty() || ls(s, dp[mask][pr])) { dp[mask][pr] = s; Expression e(s, mask, pr); q.insert(e); } } int main() { add(2, "x", X_TABLE); add(2, "y", Y_TABLE); add(2, "z", Z_TABLE); while (!q.empty()) { auto e = *q.begin(); q.erase(q.begin()); if (e.p == 2) { add(2, "!" + e.e, ~e.t & FULL); add(1, e.e, e.t); } if (e.p == 1) { for (int mask = 0; mask < FULL; ++mask) { if (!dp[mask][2].empty()) { add(1, dp[mask][2] + "&" + e.e, mask & e.t); add(1, e.e + "&" + dp[mask][2], mask & e.t); } } add(2, "(" + e.e + ")", e.t); add(0, e.e, e.t); } if (e.p == 0) { for (int mask = 0; mask < FULL; ++mask) { for (int pr = 1; pr <= 2; ++pr) { if (!dp[mask][pr].empty()) { add(0, dp[mask][pr] + "|" + e.e, mask | e.t); add(0, e.e + "|" + dp[mask][pr], mask | e.t); } } } add(2, "(" + e.e + ")", e.t); } } int n; cin >> n; while (n--) { string s; cin >> s; int mask = 0; for (int i = 0; i < 8; ++i) { if (s[i] == '1') { mask |= (1 << i); } } cout << dp[mask][0] << endl; } return 0; }
相关文章推荐
- Hello 2018 A
- CF Hello 2015 A ST表模板
- April Fools Contest 2018[cf 愚人节专场题解]
- Hello 2018 B
- Hello 2018 C. Party Lemonade (dp好题)
- codeforces Hello 2018(A-E)
- printf("Hello 2018!");
- Codeforces Hello 2018 - A - Modular Exponentiation
- codeforces Hello 2018(A-E)
- 151 - ZOJ Monthly, March 2018 - H同CF 415D Mashmokh and ACM(DP)
- Codeforces Hello 2018 - B - Christmas Spruce
- Hello 2018 - (A,B,C)
- Codeforces Hello 2018 B.Christmas Spruce
- codeforces Hello 2018(A-E)
- Codeforces Hello 2018 - C - Party Lemonade
- codeforces Hello 2018 C. Party Lemonade(贪心)
- Hello 2018 A - D 题解
- codeforces Hello 2018(A-E)
- Hello 2018, Bye 2017
- Codeforces Hello 2018 - D - Too Easy Problems