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喜欢研究进 ...
随机推荐
- lol人物模型提取(四)
在淘宝上联系了一个3d打印服务的卖家,他要我转成stl.obj.xt.xst.igs任意一种格式给他发过去,我就把它转成了obj格式给他发过去了. 然后他那边打开是这样的,没有贴图,看上去模型 ...
- [OS] 信号量(Semaphore)
一个信号量S是一个整型量,除对其初始化外,它只能由两个原子操作P和V来访问.P和V的名称来源于荷兰文proberen(测试)和verhogen(增量),后面亦将P/V操作分别称作wait(), sig ...
- [CF1083B]The Fair Nut and Strings
题目大意:在给定的长度为$n(n\leqslant5\times10^5)$的字符串$A$和字符串$B$中找到最多$k$个字符串,使得这$k$个字符串不同的前缀字符串的数量最多(只包含字符$a$和$b ...
- BZOJ4104 [Thu Summer Camp 2015]解密运算 【乱搞】
题目链接 BZOJ4104 题解 我们将已知字符排序,由循环就可以得到一个对应关系 如样例就是: 0->第5行 1->第1行 1->第2行 1->第3行 1->第5行 2 ...
- [BZOJ1106/POI2007]Tet立方体大作战
Description 一个叫做立方体大作战的游戏风靡整个Byteotia.这个游戏的规则是相当复杂的,所以我们只介绍他的简单规则:给定玩家一个有2n个元素的栈,元素一个叠一个地放置.这些元素拥有n个 ...
- POI 2018.10.21
[POI2008]TRO-Triangles https://www.cnblogs.com/GXZlegend/p/7509699.html 平面上有N个点. 求出所有以这N个点为顶点的三角形的面积 ...
- 8VC Venture Cup 2016 - Final Round (Div. 2 Edition) A
A. Orchestra time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- Dumpsdecrypted
Dumps decrypted mach-o files from encrypted iPhone applications from memory to disk. This tool is ne ...
- 搭建JavaWeb应用开发环境
下载和安装Tomcat服务器 下载Tomcat安装程序包:http://tomcat.apache.org/,下载一个zip版本,解压到本地即完成了Tomcat的安装. 测试是否安装成功:进入Tomc ...
- Centos6.5+Python2.7 +ffmpeg+opencv2自动安装脚本
今天安装opencv折腾了多个小时,为以后安装少走弯路,脚本安装 完整 脚本如下: #! /bin/bash sudo yum install -y gcc g++ gtk+-devel libjpe ...