2018百度之星程序设计大赛 - 资格赛 A B C E F
1001
思路:
问题数m是不超过10的,所以我们对问题数 m 进行状态压缩,每个状态可以得到一些问题的集合,这些问题集合是属于这 m 个问题集合中的,并且不会重复的,所以我们根据每个状态可以得到 n 个人在这个状态下的回答情况,因为每个问题的答案只有 ‘A’ 或者 ‘B’ ,所以我将这 n 个人在这个状态下的回答情况变成一个二进制数(‘A’ 看成 0 ‘B’ 看成 1),这样就可以很简单的得到这 n 个人中有多少对不同的答案,再和 k 进行比较计数即可。
代码:
#include<cstdio>
#include<cstring>
using namespace std;const int maxn=1000+10;char ch[maxn][20];
int kaven[maxn];
int M[1<<11];int main(){int T,C=0;scanf("%d",&T);while(T--){int n,m,k;scanf("%d%d%d",&n,&m,&k);getchar();for(int i=1;i<=n;i++) scanf("%s",ch[i]);if(n*(n-1)/2<k){printf("Case #%d: 0\n",++C);continue;}int cnt=0;for(int i=1;i<(1<<m);i++){for(int j=1;j<=n;j++){int tot=0;for(int t=0;t<m;t++){if(i>>t&1 && ch[j][t]=='B'){tot+=(1<<t);}}kaven[j]=tot;M[tot]=0;}int num=0;for(int j=1;j<=n;j++){int cnt= ++M[kaven[j]];//printf("%d %d\n",kaven[j],M[kaven[j]]);num+=(j-cnt);}if(num>=k) cnt++;}printf("Case #%d: %d\n",++C,cnt);}
}
1002
思路:
我是用莫队写的,可能写这种区间问题我用莫队写习惯了,莫队写这个题也很简单,当然其他的想法也可以,比如前缀和啥的,我就不重复写了,下面是莫队思路的代码
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;const int maxn=100000+100;char ch[maxn];
struct Mo{int l,r;int id;
}mo[maxn];
int R[maxn];
int Ans[maxn];
int num[30];inline bool cmp(Mo a,Mo b){return R[a.l]==R[b.l]?a.r<b.r:R[a.l]<R[b.l];
}inline void kaven(int ind,int v){int tmp=(int)(ch[ind]-'A');num[tmp]+=v;
}int main(){int T,C=0;scanf("%d",&T);while(T--){int n,m;scanf("%d%d",&n,&m);getchar();scanf("%s",ch+1);int l=1,r=0;int size=sqrt(1.0*n);for(int i=0;i<30;i++) num[i]=0;for(int i=1;i<=n;i++) R[i]=i/size;for(int i=1;i<=m;i++) scanf("%d%d",&mo[i].l,&mo[i].r),mo[i].id=i;sort(mo+1,mo+1+m,cmp);for(int i=1;i<=m;i++){while(l>mo[i].l) kaven(l-1,1),l--;while(r<mo[i].r) kaven(r+1,1),r++;while(l<mo[i].l) kaven(l,-1),l++;while(r>mo[i].r) kaven(r,-1),r--;int key;for(key=0;key<=25;key++) if(num[key]) break;Ans[mo[i].id]=num[key];}printf("Case #%d:\n",++C);for(int i=1;i<=m;i++) printf("%d\n",Ans[i]);}
}
1003
思路:
条件 x[i] + y[j] <= a[i][j]
求 x[1]+x[2]+…+x[n]+y[1]+y[2]+…+y[n]的最大值
我们可以把 x[] 和 y[] 进行两两组合
比如:n=2的情况
第一种:x[1] + y[1],x[2] + y[2] 即 a[1][1] ,a[2][2]
第二种:x[1] + y[2],x[2] + y[1] 即 a[1][2] ,a[2][1]
所以答案就是 min( a[1][1] +a[2][2], a[1][2] +a[2][1] )
所以答案就是 在矩阵不同行不同列中取 n 个数的最小值,用 KM 即可
怪我 KM 的板子质量太差了,比赛的时候无限 T
下面代码是我新的 KM 板子
代码:
DFS实现
#include<cstdio>
#include<algorithm>
using namespace std;#define MEM(a,b,start,end) for(int ii=start;ii<=end;ii++) a[ii]=b
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
const int INF=0x3f3f3f3f;
const int maxn=250;int xy[maxn][maxn],match[maxn],slack[maxn],valx[maxn],valy[maxn];
bool visx[maxn],visy[maxn];
int n;inline bool DFS(int u,int key=1){if(visx[u]) return false;visx[u]=true;for(int i=1;i<=n;i++){if(!visy[i]){int tmp=valx[u]+valy[i]-xy[u][i];if(tmp==0){visy[i]=true;if(match[i]==-1 || DFS(match[i],key)){if(key) match[i]=u;return true;}}else slack[i]=min(slack[i],tmp);}}return false;
}long long KM(){for(int i=1;i<=n;i++){MEM(visx,false,1,n);MEM(visy,false,1,n);MEM(slack,INF,1,n);if(DFS(i)) continue;bool isok=true;while(isok){int tmp=INF;for(int j=1;j<=n;j++){if(!visy[j] && tmp>slack[j]) tmp=slack[j];}for(int j=1;j<=n;j++){if(visx[j]) valx[j]-=tmp;if(visy[j]) valy[j]+=tmp;else slack[j]-=tmp;}for(int j=1;j<=n;j++){if(!visy[j] && slack[j]==0){visy[j]=true;if(match[j]==-1 || DFS(match[j],0)){isok=false;break;}}}}MEM(visx,false,1,n);MEM(visy,false,1,n);DFS(i);}long long res=0;for(int i=1;i<=n;i++) res+=xy[match[i]][i];return res;
}int main(){int T,C=0;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;i++){valx[i]=-INF;valy[i]=0;match[i]=-1;for(int j=1;j<=n;j++) scanf("%d",&xy[i][j]),xy[i][j]*=-1,valx[i]=max(valx[i],xy[i][j]);}printf("Case #%d: %lld\n",++C,-KM());}
}
BFS实现
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;#define MEM(a,b,start,end) for(int ii=start;ii<=end;ii++) a[ii]=b
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
const int INF=0x3f3f3f3f;
const int maxn=250;int xy[maxn][maxn],valx[maxn],valy[maxn],slack[maxn],l[maxn],r[maxn],pre[maxn];
bool visx[maxn],visy[maxn];
int n;void BFS(int u){queue<int> Q;Q.push(u);visx[u]=true;while(1){while(!Q.empty()){int x=Q.front(); Q.pop();for(int y=1;y<=n;y++){int tmp=valx[x]+valy[y]-xy[x][y];if(!visy[y] && tmp<=slack[y]){pre[y]=x;if(!tmp){if(!l[y]){for(;y;l[y]=pre[y],swap(y,r[pre[y]]));return;} else{visx[l[y]]=visy[y]=true;Q.push(l[y]);}} else{slack[y]=tmp;}}}}int tmp=INF;int node=u;for(int i=1;i<=n;i++){if(!visy[i] && slack[i]<=tmp){node=i,tmp=slack[i];}}for(int i=1;i<=n;i++){if(visx[i]) valx[i]-=tmp;if(visy[i]) valy[i]+=tmp;else slack[i]-=tmp;}if(!l[node]){for(;node;l[node]=pre[node],swap(node,r[pre[node]]));return;} else{visx[l[node]]=visy[node]=true;Q.push(l[node]);}}
}void KM(){for(int i=1;i<=n;i++){MEM(visx,false,1,n);MEM(visy,false,1,n);MEM(slack,INF,1,n);BFS(i);}
}int main(){int T,C=0;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;i++){valx[i]=-INF;valy[i]=0;l[i]=r[i]=pre[i]=0;for(int j=1;j<=n;j++) scanf("%d",&xy[i][j]),xy[i][j]*=-1,valx[i]=max(valx[i],xy[i][j]);}KM();long long res=0;for (int i=1;i<=n;i++) res+=(-valx[i]-valy[i]);printf("Case #%d: %I64d\n",++C,res);}
}
1005
思路:
因为数据随机,所以数据中每种排列的最长上升子序列长度的期望是 n^(0.5)(题解说的,我也不知道),所以比赛的时候,我想了一个动态规划的解法,dp[ind][len]=sum(dp[res][len-1]) (ind>res,id[res] < id[ind] ,id[i] 表示 i 这个数在排列中的位置,也就是 ind 在排列中,前面比它小的数- res ) ,这个 sum(dp[res][len-1]) 用树状数组来维护就可以了,当时感觉复杂度还是很高,又想了想,当长度为 len 的最长上升子序列不存在时,长度为 len+1 的最长上升子序列肯定不存在,所以就加了个判断条件,因为数据随机,我觉得应该可以A,没想到可以1A,具体看代码吧,因为开 dp[][] 这个二位数组感觉没什么用,所以你可以把下面代码中的tree[][](树状数组)当作是dp[][]。。。
代码:
#include<cstdio>
#include<cstring>
using namespace std;const int maxn=10000+10;
const int mod=1e9+7;int tree[maxn][maxn],ans[maxn];
int n;inline int lowbit(int x){return x&(-x);
}inline void Add(int ind,int len,int v){while(ind<=n){tree[ind][len]=(tree[ind][len]+v)%mod;ind+=lowbit(ind);}
}inline int getSum(int ind,int len){int sum=0;while(ind>0){sum=(sum+tree[ind][len])%mod;ind-=lowbit(ind);}return sum;
} int main(){int T,C=0;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&ans[i]);for(int i=1;i<=n;i++){Add(ans[i],1,1);for(int j=2;j<=i;j++){int val=getSum(ans[i]-1,j-1);if(val==0) break;Add(ans[i],j,val);}}int i;int val=1;printf("Case #%d: ",++C);for(i=1;i<=n;i++){if(val) {val=getSum(n,i);for(int j=1;j<=n;j++) tree[j][i]=0;}else val=0;printf("%d%c",val,i==n?'\n':' ');}}
}
1006
思路:
复制一下Q神的题解:
满足条件的 k 条边必然包含一个由红色边和绿色边构成的最小生成树或者一个由蓝色边和绿色边构成的最小生成树,不难证明一个图中所有最小生成树的边权集合是相同的,于是可以对两种情况分别求出一个最小生成树,再按照边权从小到大的顺序加入不在最小生成树上的边。
代码:
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;#define MEM(a,b) memset(a,b,sizeof(a))
const int maxn=110;struct Edge{int from,to,w;char type;int id;Edge(int from_,int to_,int w_,char type_,int id_):from(from_),to(to_),w(w_),type(type_),id(id_){}
};
vector<Edge>RG,BG;
int fa[maxn][2];
bool vis[maxn<<2][2];
int n,m;inline bool cmp(Edge a,Edge b){return a.w<b.w;
}inline int Find(int x,int reg){if(x!=fa[x][reg]) fa[x][reg]=Find(fa[x][reg],reg);return fa[x][reg];
}inline void Union(int x,int y,int reg){int X=Find(x,reg);int Y=Find(y,reg);if(X<Y) fa[Y][reg]=X;else fa[X][reg]=Y;
}inline pair<int,int> kaven(vector<Edge> G,int reg,char type1,char type2){int mst=0; //最小生成树 int cnt=0; //边数for(int i=0;i<m*2 && cnt<n-1;i++){Edge e=G[i];int from=e.from,to=e.to,w=e.w,type=e.type;if(type!=type1 && type!=type2) continue;if(Find(from,reg)!=Find(to,reg)){Union(from,to,reg);mst+=w;cnt++;vis[e.id][reg]=vis[e.id^1][reg]=true;//printf("---%d %d---\n",from,to);}}//printf("%d %d\n",mst,cnt);if(cnt==n-1) return make_pair(mst,cnt);else return make_pair(1e9,cnt);
}int main(){int T,C=0;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);RG.clear();BG.clear(); for(int i=1;i<=m;i++){int from,to,w;char type;scanf("%d%d%d %c",&from,&to,&w,&type);//if(type<'A' || type>'Z') type=type-'a'+'A';RG.push_back(Edge(from,to,w,type,2*i));RG.push_back(Edge(to,from,w,type,2*i+1));BG.push_back(Edge(from,to,w,type,2*i));BG.push_back(Edge(to,from,w,type,2*i+1));//printf("%d %d %d %c\n",from,to,w,type);}sort(RG.begin(),RG.end(),cmp);sort(BG.begin(),BG.end(),cmp);MEM(vis,false);for(int i=1;i<=n;i++) fa[i][0]=fa[i][1]=i;pair<int,int> rg=kaven(RG,0,'R','G'); pair<int,int> bg=kaven(BG,1,'B','G');printf("Case #%d:\n",++C);if(rg.first==1e9 && bg.first==1e9){for(int i=1;i<=m;i++) printf("-1\n");}else{int minedge=min(rg.second,bg.second);for(int i=1;i<minedge;i++) printf("-1\n");for(int i=minedge;i<=m;i++){int minval=1e9;if(rg.first!=1e9 && rg.second<i){for(int j=0;j<m*2;j++){Edge e=RG[j];int w=e.w;if(!vis[e.id][0]){rg.first+=w;rg.second++;vis[e.id][0]=vis[e.id^1][0]=true;break;}}}if(bg.first!=1e9 && bg.second<i){for(int j=0;j<m*2;j++){Edge e=BG[j];int w=e.w;if(!vis[e.id][1]){bg.first+=w;bg.second++;vis[e.id][1]=vis[e.id^1][1]=true;break;}}}if(rg.second==i) minval=min(minval,rg.first);if(bg.second==i) minval=min(minval,bg.first);printf("%d\n",minval==1e9?-1:minval);}}}
}
2018百度之星程序设计大赛 - 资格赛 A B C E F相关推荐
- 2018百度之星程序设计大赛 - 资格赛 hdu6345(找区间最小值)
子串查询 Time Limit: 3500/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Sub ...
- 2018百度之星程序设计大赛资格赛(4道题的答案)
目前是百度之星的资格赛比赛时间,写对一道题就可以进入后面的比赛了,我们初赛再见咯.明明昨天就上传该文章,可惜图片太多一直列为待审核,现在图片都删了,日后再来详细补充题目吧. ###调查问卷 #incl ...
- 2018百度之星程序设计大赛 - 资格赛 1002 子串查询
子串查询 Accepts: 1262 Submissions: 5335 Time Limit: 3500/3000 MS (Java/Others) Memory Limit: 262144/262 ...
- 2018百度之星程序设计大赛 - 资格赛 P1006三原色图(MST,并查集)
problem 给一张n个点m条边的有向图,每条边有一个正整数权值以及一种色光三原色红.绿.蓝之一的颜色. 恰好选出k条边,满足只用这k条边之中的红色边和绿色边(或者蓝色边和绿色边)就能使n个点之间两 ...
- 2018百度之星程序设计大赛-资格赛P1002子串查询(前缀和)
因为过关要求貌似是随便A掉一道题,,,还实时给了AC率,不是摆明了让我挑最水的题写吗.. problem 给定一个字符串A[1,n]. 询问q次,A[l,r]内字典序最小的连续非空子串有多少次重复. ...
- 2018百度之星程序设计大赛 - 资格赛
BB 好了我活了 这么长时间不写题就是会变菜啊 这种题写这么长时间QAQ T1 这个题刚看到的时候一脸mb 然后看到数据范围就放心了 就写了个子集枚举就交上去了 但是要注意的是最后统计答案的时候,是每 ...
- hdu6383(2018 “百度之星”程序设计大赛 - 初赛(B))
p1m2 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Sub ...
- hdu6380(2018 “百度之星”程序设计大赛 - 初赛(B))
degree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total S ...
- hdu6375(2018 “百度之星”程序设计大赛 - 初赛(A))
度度熊学队列 Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total S ...
最新文章
- TinaFace:人脸检测新纪录
- 查询name和age当name相同时选择age最大的
- 加快windows上对大文件,以及很多很多小文件进行不同磁盘拷贝的速度——windows上的最快拷贝软件FastCopy
- 随时牵手,不要随意分手
- numpy 是否为零_一文看懂Numpy统计计算、数组比较
- 解决Eclipse中SVN版本比较中文乱码问题
- stata中心化处理_带有stata第2部分自定义配色方案的covid 19可视化
- Do you have an English name? 你有英文名吗?
- JAVAWEB入门之Servlet_体系结构
- 面试官:Object o = new Object() 占用了多少字节?
- 实验7 寻址方式在结构化数据访问中的应用
- java高级工程师工资_java高级工程师工资为何让人艳羡不已
- 前端测试之用户体验测试
- 点集求最小包围盒OBB算法
- 未来家用计算机发展趋势,容易写的计算机未来发展趋势论文选题 计算机未来发展趋势论文题目如何取...
- DeepLearning花书阅读记录(1)
- python 监听键盘输入并收集数据进行分析
- 虚拟现实内容开发收费标准
- JavaScript实现模板生成大量数据的方法(附代码)
- 如何计算给定二叉树中的叶节点数?