CSUST选拔赛题解
本鶸鸡于本月10号参加了蔽校的选拔赛,成绩差的死,大部分的题都是赛后花了好长时间才补出来的,其中有些题还是靠QAQorz大佬帮忙才能解决,感谢Qls对我的帮助~接下来就附带上我的暴力题解,大佬们有更好的想法请一定要告诉我啊~
Problem A: 灾区重建
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=0
这题求的是最大生成树,我用的是kruskal算法,代码如下:
#include <bits/stdc++.h>
using namespace std; const int inf=0x3f3f3f3f;
const int maxn=1e6+; int t,n,m;
int fa[maxn],r[maxn]; struct edge{
int u,v,w;
}es[maxn]; bool cmp(const edge& e1,const edge& e2){
return e1.w>e2.w;
} void init(int n){
for(int i=;i<n;i++){
fa[i]=i;
r[i]=;
}
} int fi(int x){
return fa[x]==x?x:fa[x]=fi(fa[x]);
} void unite(int x,int y){
int p1=fi(x),p2=fi(y);
if(p1==p2) return;
if(r[p1]>r[p2]) fa[p2]=p1;
else{
fa[p1]=p2;
if(r[p1]==r[p2]) r[p2]++;
}
} bool check(int x,int y){
return fi(x)==fi(y);
} int main(){
scanf("%d",&t);
for(int k=;k<=t;k++){
scanf("%d%d",&n,&m);
for(int i=;i<m;i++){
scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].w);
}
init(n);
int ans=inf;
sort(es,es+m,cmp);
for(int i=;i<m;i++){
edge e=es[i];
if(!check(e.u,e.v)){
unite(e.u,e.v);
ans=min(ans,e.w);
}
}
printf("Case #%d: %d\n",k,ans);
}
}
Problem B: 洗衣
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=1
本题是一个贪心题,不过很多方法会被T,貌似区间取点也会被T。我采用的是借用优先队列,先将所有衣服按照开始时间排序,然后用优先队列对已经入列的衣服的结束时间进行维护。未入列的衣服每次与队列第一个元素进行比较,如果它的开始时间小于第一个元素的结束时间,那么肯定需要新开一台洗衣机;否则,不用问了,把第一个元素踢了,将这件衣服请进队列==!QAQorz大佬说本题可以采用线段树+离散化过,大家坐等她的博客更新此种方法吧,至于她更新时间嘛……emmm,我也不知道~
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std; const int maxn=1e5+;
int n; struct node{
int s,t;
bool operator < (const node& a) const
{
return t>a.t || (t==a.t && s>a.s);
}
}l[maxn]; bool cmp(const node& x,const node& y){
return x.s==y.s?(x.t<y.t):(x.s<y.s);
} int main(){
while(~scanf("%d",&n)){
for(int i=;i<n;i++){
scanf("%d%d",&l[i].s,&l[i].t);
}
priority_queue<node> q;
sort(l,l+n,cmp);
if(n==) printf("1\n");
else{
q.push(l[]);
for(int i=;i<n;i++){
node f=q.top();
if(l[i].s<f.t){
q.push(l[i]);
}
else{
q.pop();
q.push(l[i]);
}
}
printf("%d\n",q.size());
}
}
}
Problem C: 先有durong后有天
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=2
具体解释再代码注释内,如果还不懂请在评论区提问,我会尽力为你解答
#include <cstdio>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std; const int inf=0x3f3f3f3f;
const int maxn=; int n,m,s1,e1,s2,e2,t1,t2;
int d[maxn][maxn]; vector<int> G[maxn]; void init(){
for(int i=;i<maxn;i++){
G[i].clear();
}
for(int i=;i<maxn;i++){
for(int j=;j<maxn;j++){
if(i==j) d[i][j]=;
else d[i][j]=d[j][i]=inf;
}
}
} void bfs(int u){
queue<int> q;
q.push(u);
while(!q.empty()){
int t=q.front();q.pop();
for(int i=;i<G[t].size();i++){
int p=G[t][i];
if(d[u][p]>=inf){
d[u][p]=d[u][t]+;
q.push(p);
}
}
}
} int main(){
while(~scanf("%d%d",&n,&m)){
init();
int a,b;
for(int i=;i<m;i++){
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=;i<=n;i++){
bfs(i);
}
scanf("%d%d%d%d%d%d",&s1,&e1,&t1,&s2,&e2,&t2);
int ans1=min(d[s1][e1],d[e1][s1]),ans2=min(d[s2][e2],d[e2][s2]);
if(ans1>t1 || ans2>t2){ //如果不卖任何一条路都不能达到要求,那么就是不满足题意,输出-1;
printf("-1\n");
continue;
}
else{
int ans=ans1+ans2;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
int tt1=min(d[s1][i]+d[i][j]+d[j][e1],d[e1][i]+d[i][j]+d[j][s1]); //因为我采用的求距离是有方向的,所以还得反过来比价一下;
int tt2=min(d[s2][i]+d[i][j]+d[j][e2],d[e2][i]+d[i][j]+d[j][s2]);
if(tt1==ans1 && tt2==ans2){ //如果tt1==ans1且tt2==ans2,那么就说明i和j是两条最短路中间重合部分的起点和终点;
ans=min(ans,ans1+ans2-d[i][j]);
}
}
}
printf("%d\n",m-ans); //将不是最短路经过的路全部卖了就行……
}
}
}
(对于此题,我想问一句,,durong大佬没钱是不是因为将所有的前都拿去买衣服了?durong大佬对衣服真的是情有独钟钟)
Problem D: 一棵树
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=3
题目描述:给你一颗有n个顶点的树。树上有n-1条边,边上的权值c代表一对顶点(u,v)的距离,定义为x到y上的距离,求
数据范围:T<=10,n<=100,000,1<=c<=100,000
Time Limit: 1 Sec Memory Limit: 128 MB
这个题就是一个树上递归,通过找规律找出每条路需要通过的次数,然后在dfs时顺便将结果算出来。寻找规律的流程如下图:
#include <cstdio>
#include <vector>
using namespace std; typedef long long ll;
const int maxn=1e5+;
int t,n;
ll ed[maxn],sum[maxn]; //ed是用来存放第i点的子节点数+1; struct edge{
int v;
ll w;
edge(int v=,ll w=):v(v),w(w){}
}; vector<edge> G[maxn]; void init(){
for(int i=;i<maxn;i++){
ed[i]=;
sum[i]=;
G[i].clear();
}
} void dfs(int u,int p){
ed[u]=;
for(int i=;i<G[u].size();i++){
int v=G[u][i].v;
ll w=G[u][i].w;
if(v!=p){
dfs(v,u);
ed[u]+=ed[v];
sum[u]+=sum[v]+ed[v]*(n-ed[v])*w;
}
}
} int main(){
scanf("%d",&t);
while(t--){
init();
scanf("%d",&n);
int u,v;
ll w;
for(int i=;i<n;i++){
scanf("%d%d%lld",&u,&v,&w);
G[u].push_back(edge(v,w));
G[v].push_back(edge(u,w));
}
dfs(,-);
printf("%lld\n",sum[]);
}
}
Problem E: 杜荣NB
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=4
这题就是xjb打表就行,因为给的时限有5s。比赛时因为题面错了,将x的上限设为1e8,这样需要数位dp好像,前面也说过了,我的dp非常菜,所以当时挣扎了一段时间就放弃了==!
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std; const int maxn=1e7+;
int b,t,x;
int rk[maxn];
set<int> s; int main(){
while(~scanf("%d",&b)){
int r=;
s.clear();
for(int i=;i<=1e7;i++){
int m=i,sum=;
while(m){
sum+=m%;
m/=;
}
if(sum==b){
rk[r++]=i;
s.insert(i);
}
}
scanf("%d",&t);
while(t--){
scanf("%d",&x);
if(!s.count(x)){
printf("durongNB\n");
}
else{
int u=r-,l=;
if(rk[u]==x){
printf("%d\n",u+);
}
else if(rk[]==x){
printf("1\n");
}
else{
int mid;
while(u>l){
mid=(u+l)/;
if(rk[mid]==x){
printf("%d\n",mid+);
break;
}
else if(rk[mid]>x){
u=mid;
}
else{
l=mid;
}
}
}
}
}
}
}
Problem F: 挑战迷宫
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=5
此题是一个比较裸(或者说是纯?)的LCA,至于算距离嘛,在dfs时顺便算出当前节点到根节点的距离,之后就将询问的两个节点到根节点的距离相加再减去二者最近公共祖宗节点到根节点的距离即可,代码实现如下:
#include <cstdio>
#include <vector>
using namespace std; const int maxn=1e5+;
int n,m;
int pa[maxn][],deep[maxn],cost[maxn]; struct edge{
int v,l;
edge(int v=,int l=):v(v),l(l){}
}; vector<edge> G[maxn]; void dfs(int id,int p,int d){
pa[id][]=p;
deep[id]=d;
for(int i=;i<G[id].size();i++){
int a=G[id][i].v;
if(a!=p){
cost[a]=cost[id]+G[id][i].l;
dfs(a,id,d+);
}
}
} void lca(){
for(int i=;i<=n;i++){
for(int j=;(<<j)<=n;j++){
pa[i][j]=-;
}
}
for(int j=;(<<j)<=n;j++){
for(int i=;i<=n;i++){
if(pa[i][j-]!=-){
pa[i][j]=pa[pa[i][j-]][j-];
}
}
}
} int query(int u,int v){
if(deep[u]<deep[v]) swap(u,v);
int dd;
for(dd=;(<<(dd+))<=deep[u];dd++);
for(int i=dd;i>=;i--){
if(deep[u]-(<<i)>=deep[v]){
u=pa[u][i];
}
}
if(u==v) return u;
for(int i=dd;i>=;i--){
if(pa[u][i]!=- && pa[u][i]!=pa[v][i]){
u=pa[u][i];
v=pa[v][i];
}
}
return pa[u][];
} int main(){
while(~scanf("%d",&n)){
int u,v,w;
for(int i=;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(edge(v,w));
G[v].push_back(edge(u,w));
}
dfs(,-,);
lca();
scanf("%d",&m);
for(int i=;i<m;i++){
scanf("%d%d",&u,&v);
printf("%d\n",cost[u]+cost[v]-*cost[query(u,v)]);
}
}
}
Problem G: 括号匹配
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=6
此题……QAQorz教我的,我的dp菜的一匹,只会简单的01背包系列,我只解释一下这个dp的状态算了,dp[i][j]存的是第i个位置第j层的方案数(表述好像不太清楚,那就自行体会吧,以后再来填坑算了-_-!),代码实现如下:
#include <cstdio>
#include <cstring> const int maxn=;
const int mod=1e9+;
int t;
char s[maxn];
int dp[maxn][maxn]; int main(){
scanf("%d",&t);
while(t--){
scanf("%s",s);
int len=strlen(s);
if(len%){
printf("0\n");
continue;
}
memset(dp,,sizeof(dp));
dp[][]=;
for(int i=;i<len;i++){
for(int j=;j<len/+;j++){
if(s[i]=='('){
if(j>) dp[i+][j]=dp[i][j-];
else dp[i+][j]=;
}
else if(s[i]==')'){
if(j<len/) dp[i+][j]=dp[i][j+];
else dp[i+][j]=;
}
else{
dp[i+][j]=;
if(j>) dp[i+][j]=dp[i][j-]+dp[i][j+];
else dp[i+][j]=dp[i+][j];
if(j<len/) dp[i+][j]=dp[i][j+]+dp[i][j-];
else dp[i+][j]=dp[i+][j];
}
dp[i+][j]%=mod;
}
}
printf("%d\n",dp[len][]%mod);
}
}
Problem H: 逃出监狱
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=7
题目描述:给你一个n*m的图,地图上'.'代表可以走的地方,而'#'代表障碍物不能走,
'A'代表小偷,'B'代表警察,'E'代表出口。每个位置可以向(上,下,左,
右)四个方向走一格,花费一个单位时间,现在给出小偷,警察和出口所在
位置,警察为了捉住小偷会先到出口的位置守株待兔,如果警察在小偷之前
或同时到达出口,或者小偷到达不了出口,输出"No",否则输出"Yes"。
数据范围:T<=50,n<=500,m<=500
Time Limit: 1 Sec Memory Limit: 128 MB
这个因为是两个起点一个终点,所以完全可以从终点开始搜,完全没必要跑两个bfs。但是比赛时一直在纠结警察会不会在路上抓到小偷,然后思考了半小时,默默地看着好几个人A了,最后实在没办法了,就试了下不能在路上抓到小偷,,然后就A了,然后就开始思考为啥自己那么喜欢多想,不然就是1A了-_-!
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std; const int inf=0x3f3f3f3f;
int w,h,ans;
int sx,sy,k;
char mp[][];
int vis[][]; struct node{
int x,y,step;
}nw,nxt; int dx[]={,-,,},dy[]={,,,-}; int bfs(int x,int y){
nw.x=x,nw.y=y,nw.step=;
vis[y][x]=;
queue<node> q;
q.push(nw);
while(!q.empty()){
nw=q.front();q.pop();
if(mp[nw.y][nw.x]=='*'){
memset(vis,,sizeof(vis));
vis[nw.y][nw.x]=;
mp[nw.y][nw.x]='.';
if(k==){
k--;
return nw.step;
}
k--;
return nw.step+bfs(nw.x,nw.y);
}
for(int i=;i<;i++){
nxt.x=nw.x+dx[i],nxt.y=nw.y+dy[i];
if(nxt.x>= && nxt.x<h && nxt.y>= && nxt.y<w && vis[nxt.y][nxt.x]== && mp[nxt.y][nxt.x]!='x'){
nxt.step=nw.step+;
vis[nxt.y][nxt.x]=;
q.push(nxt);
}
}
}
return ;
} int main(){
while(~scanf("%d%d",&h,&w)){
if(w== && h==) break;
for(int i=;i<w;i++){
scanf("%s",mp[i]);
}
k=,ans=;
for(int i=;i<w;i++){
for(int j=;j<h;j++){
if(mp[i][j]=='o'){
sx=j,sy=i;
}
if(mp[i][j]=='*'){
k++;
}
}
}
ans=bfs(sx,sy);
if(k>){
printf("-1\n");
}
else{
printf("%d\n",ans);
}
}
}
Problem I: 简单题
题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?cid=1015&pid=8
题目描述:给你N个数Q次操作。其中每次操作包括1.从l到r的所有元素都加x和查询,2.求第l个元素到第r个元素间的数据的平均值,保留两位小数
数据范围:N <= 100000,Q <= 100000,数列中的每个元素 <= 100,0<=X<=100
Time Limit: 1 Sec Memory Limit: 128 MB
这题就是一个纯裸的线段树,但是比赛时由于带的板子出了问题,没发现&&忘记开long long猛WA3发-_-!,还好及时发现,最后竟然还拿了本题的一血(雾。所以这题就是带副没有错误的好板子(-_-!)和记得开long long就行~
#include <cstdio> typedef long long ll;
const int maxn=1e5+; int t,n,q;
int a[maxn]; struct node{
int l,r;
ll sum,lazy;
}tree[maxn*]; void push_down(int i){
if(tree[i].lazy!= && tree[i].l!=tree[i].r){
ll x=tree[i].lazy;
tree[i*].lazy+=x;
tree[i*+].lazy+=x;
tree[i*].sum+=x*(tree[i*].r-tree[i*].l+);
tree[i*+].sum+=x*(tree[i*+].r-tree[i*+].l+);
tree[i].lazy=;
}
return;
} void push_up(int i){
tree[i].sum=tree[i*].sum+tree[i*+].sum;
return;
} void build(int i,int l,int r){
tree[i].l=l,tree[i].r=r;
tree[i].lazy=;
if(l==r){
tree[i].sum=a[l];
return;
}
int mid=(l+r)/;
build(i*,l,mid);
build(i*+,mid+,r);
push_up(i);
} void update(int i,int l,int r,ll x){
push_down(i);
if(tree[i].r==r &&tree[i].l==l){
tree[i].sum+=x*(r-l+);
tree[i].lazy+=x;
return;
}
int mid=(tree[i].l+tree[i].r)/;
if(r<=mid) update(i*,l,r,x);
else if(l>mid) update(i*+,l,r,x);
else{
update(i*,l,mid,x);
update(i*+,mid+,r,x);
}
push_up(i);
} ll query(int i,int l,int r){
push_down(i);
if(tree[i].l==l &&tree[i].r==r){
return tree[i].sum;
}
int mid=(tree[i].l+tree[i].r)/;
if(l>mid) return query(i*+,l,r);
else if(r<=mid) return query(i*,l,r);
else{
return query(i*,l,mid)+query(i*+,mid+,r);
}
} int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
build(,,n);
scanf("%d",&q);
int x;
for(int i=;i<q;i++){
scanf("%d",&x);
if(x){
int l,r;
scanf("%d%d",&l,&r);
double ans=1.0*query(,l,r)/(r-l+);
printf("%.2f\n",ans);
}
else{
int l,r;
ll s;
scanf("%d%d%lld",&l,&r,&s);
update(,l,r,s);
}
}
}
}
CSUST选拔赛题解的更多相关文章
- CSUST 集训队选拔赛题解
选拔赛的题解,~~~ 题目链接:请点击 A题 素数筛 + 线段树(树状数组) 先用素数筛打表,然后线段树更新,遍历求出值,O(1)查询即可 AC代码: /*num数组 是把记录 数是否存在 存在即为1 ...
- 江西理工大学南昌校区acm选拔赛题解
第一题略 第二题 #include<stdio.h> int main() { int a1,a2,a3,b1,b3,b2,c1,c2,c3,n,sum,d1,d2,d3,i; scanf ...
- ypACM社团年终赛暨实验室选拔赛题解
记得补题,题目两小时半还是挺困难ak的,毕竟我验题也验了几天的时间,题目基本没有锅.题目基本属于简单题 我的三道题都是很基本的题目,希望大家补题 这些题解都是我写的,如果有疑问可以qq问我 所有的核心 ...
- 2018年北京信息科技大学第十届程序设计竞赛暨ACM选拔赛题解
链接:https://www.nowcoder.com/acm/contest/118/A 来源:牛客网 PUBG 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语 ...
- 2019CSUST集训队选拔赛题解(二)
凛冬将至 Description 维斯特洛大陆的原住民是森林之子,他们长得如孩童一般,善于使用石器,威力值35,用树叶树枝作为衣物,在森林里繁衍生息,与万物和平相处.他们会使用古老的魔法(比如绿之视野 ...
- 2019CSUST集训队选拔赛题解(三)
PY学长的放毒题 Description 下面开始PY的香港之行,PY有n个要去的小吃店,这n个小吃店被m条路径联通起来. PY有1个传送石和n−1个传送石碎片. PY可以用传送石标记一个小吃店作为根 ...
- 2019CSUST集训队选拔赛题解(一)
来自ppq的毒瘤线段树 Sneakers Description 有一天喜欢买鞋的ppq和小伙伴来到了某一家球鞋店,球鞋店有n种球鞋,价格分别为ai,ppq在鞋店兜兜转转,发现鞋店老板会偶尔将某段 ...
- LCA倍增算法
LCA 算法是一个技巧性很强的算法. 十分感谢月老提供的模板. 这里我实现LCA是通过倍增,其实就是二进制优化. 任何一个数都可以有2的阶数实现 例如16可以由1 2 4 8组合得到 5可以由1 2 ...
- 2288: 【基础】小X转进制
2288: [基础]小X转进制 时间限制: 1 Sec 内存限制: 256 MB 提交: 1316 解决: 576 [提交] [状态] [讨论版] [命题人:ghost79] 题目描述 小X喜欢研究进 ...
随机推荐
- 活学活用wxPython
http://www.czug.org/python/wxpythoninaction/
- osg::Vec2 Vec3 Vec4
osg::Vec2可以用于保存2D纹理坐标. osg::Vec3是一个三维浮点数数组. osg::Vec4用于保存颜色数据.
- jconsole工具监控java运行情况
jconsole是jdk自带的工具.所以要先安装jdk 1.jconsole工具的路径: 通过which jconsole来查看 /usr/local/jdk1.7.0_79/bin/jconsol ...
- 让你的SilverLight程序部署在任意服务器上
是的,即使是免费的只支持HTML的空间,同样可以部署SilverLight应用.众所周知,SilverLight的部署问题其实就是.xap文件名是否能被服务器支持的问题.解决的方法无非就是添加MIME ...
- Ehcache概念篇
前言 缓存用于提供性能和减轻数据库负荷,本文在缓存概念的基础上对Ehcache进行叙述,经实践发现3.x版本高可用性不好实现,所以我采用2.x版本. Ehcache是开源.基于缓存标准.基于java的 ...
- Spring MVC之@RequestBody@ResponseBody详解
引言: 接上一篇文章讲述处理@RequestMapping的方法参数绑定之后,详细介绍下@RequestBody.@ResponseBody的具体用法和使用时机: 简介: @RequestBody 作 ...
- 【Todo】【转载】JVM学习
先参考如下这个系列<聊聊JVM> http://blog.csdn.net/column/details/talk-about-jvm.html
- 用select模拟一个socket server
1, 必须在非阻塞模式下,才能实现IO的多路复用,否则一个卡住就都卡住了.(单线程下的多路复用) 先检测自己,现在没有客户端连进来,所以会卡住. # 用select去模拟socket,实现单线程下的多 ...
- 【以前的空间】Poj 3071 Cut the Sequence
dp+单调性+平衡树 在看某篇论文中看到这道题,但是那篇论文不如这个http://www.cnblogs.com/staginner/archive/2012/04/02/2429850.html 大 ...
- [USACO06NOV]玉米田Corn Fields 状压DP
题面: 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他的 ...