NOIP2013提高组Day1题解报告


T1 转圈游戏

Description
n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位置编号,从
0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此类 推。
游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小
伙伴走到第 m+1 号位置,……,依此类推,第n − m号位置上的小伙伴走到第 0 号位置,第
n-m+1 号位置上的小伙伴走到第 1 号位置,……,第 n-1 号位置上的小伙伴顺时针走到第
m-1 号位置。
现在,一共进行了 10^k 轮,请问 x 号小伙伴最后走到了第几号位置。


解题思路
每个小朋友都要向前走m步,那么每个小朋友的相对位置不变,又由于每次走的步数恒定,所以一定会在某一次出现0号小朋友回到0号位,也就是会出现循环,只要找到循环节,通过快速幂处理10^k,整道题也就轻松解了。

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a),i_##END_=(b);i<=i_##END_;++i)
#define REP(i,a,b) for(int i=(a),i_##BEGIN_=(b);i>=i_##BEGIN_;--i)
#define M
int n,m,k,x;
int gcd(int a,int b) {if(!b)return a;return gcd(b,a%b);
}
int s;
long long Fast(int p) {long long res=10;long long ans=1;while(p) {if(p&1) {ans=1ll*ans*res%s;}res=1ll*res*res%s;p>>=1;}return ans;
}
void solve() {int tmp=gcd(n,m);long long res=1ll*n*m/tmp;s=res/m;//循环节长度long long b=Fast(k);b=1ll*(b*m%n+x)%n;printf("%lld\n",b);
}
int main() {cin>>n>>m>>k>>x;solve();return 0;
}

T2 火柴排队

Description
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑(ai −bi)^2(i∈[1,n]),其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数99,999,997 取模的结果。


解题思路
先处理最小距离,可以轻易发现,当两个序列都排好序时,对应的(ai-bi)^2之和最小。
证明:有四个数a,b,c,d,其中b>a,d>c。
生成两个序列
a,b
c,d
则这种情况两个序列的距离是:(a-c)^2+(b-d)^2—->①
我们交换c,d
这种情况两个序列的距离是:(a-d)^2+(b-c)^2—–>②
①-②得2ad+2bc-2ac-bd=2a(d-c)+2b(c-d)=2(a-b)(d-c)
由于a比b小,c比d小,所以2(a-b)(d-c)<0。则①<②。证明出排序后对应是最优的。后面也就简单了,处理最优情况下两序列对应的位置关系,求一下逆序对个数就行了

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a),i_##END_=(b);i<=i_##END_;++i)
#define REP(i,a,b) for(int i=(a),i_##BEGIN_=(b);i>=i_##BEGIN_;--i)
#define M 100005
#define md 99999997
int n;
int A[M],B[M];
struct node {int x,id;
} C[M],D[M];
int cmp(node a,node b) {return a.x<b.x;
}
int Match[M],res[M],ans;
int Bag[M];
void Merge(int L,int R) {if(L==R)return;int mid=(L+R)>>1;Merge(L,mid);Merge(mid+1,R);int i=L,j=mid+1,a=L;while(i<=mid&&j<=R) {if(res[j]<res[i]) {ans=(ans+mid-i+1)%md;Bag[a++]=res[j++];} else Bag[a++]=res[i++];}while(i<=mid)Bag[a++]=res[i++];while(j<=R)Bag[a++]=res[j++];FOR(i,L,R) {res[i]=Bag[i];}
}
void solve() {FOR(i,1,n)C[i].id=i,C[i].x=A[i];FOR(i,1,n)D[i].id=i,D[i].x=B[i];sort(C+1,C+n+1,cmp);sort(D+1,D+n+1,cmp);FOR(i,1,n) {Match[D[i].id]=C[i].id;}FOR(i,1,n) {res[Match[i]]=i;}Merge(1,n);//归并求逆序对个数printf("%d\n",ans);
}
int main() {cin>>n;FOR(i,1,n)scanf("%d",&A[i]);FOR(i,1,n)scanf("%d",&B[i]);solve();return 0;
}

T3 货车运输

Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重 量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。


解题思路
构建最大生成树,用倍增+LCA求答案。比较简单的图论题。-_-||
要注意的一点是,整个图不一定是联通的,会被分成几个联通块,把每个联通块都遍历一遍就好了。
直接上代码

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a),i_##END_=(b);i<=i_##END_;++i)
#define REP(i,a,b) for(int i=(a),i_##BEGIN_=(b);i>=i_##BEGIN_;--i)
#define M 50005
#define N 10005
int n,m,q;
struct node {int u,v,cost;
} edge[M];
struct Edge {int to,v;
};
vector<Edge>G[N];
int cmp(node a,node b) {return a.cost>b.cost;
}
int Fa[N],Tree[N],sub,Mi[N][16],fa[N][16],dep[N];
void Init() {sort(edge+1,edge+m+1,cmp);FOR(i,1,n)Fa[i]=i;
}
int getfa(int v) {return v==Fa[v]?v:Fa[v]=getfa(Fa[v]);
}
void build() {FOR(i,1,m) {int u=edge[i].u,v=edge[i].v;if(getfa(u)!=getfa(v)) {Fa[getfa(u)]=getfa(v);G[u].push_back((Edge) {v,edge[i].cost});G[v].push_back((Edge) {u,edge[i].cost});}}
}
void dfs(int x,int f) {fa[x][0]=f;Tree[x]=sub;dep[x]=dep[f]+1;FOR(i,0,G[x].size()-1) {int y=G[x][i].to;if(y==f)continue;Mi[y][0]=G[x][i].v;dfs(y,x);}
}
void Dfs() {FOR(i,1,n) {if(getfa(i)==i) {sub++;dfs(i,0);}}
}
void Pre() {FOR(j,1,15)FOR(i,1,n) {fa[i][j]=fa[fa[i][j-1]][j-1];Mi[i][j]=min(Mi[i][j-1],Mi[fa[i][j-1]][j-1]);}
}
void Up(int &x,int step) {FOR(i,0,15) {if(step&(1<<i)) {x=fa[x][i];}}
}
int LCA(int a,int b) {if(dep[a]>dep[b])swap(a,b);Up(b,dep[b]-dep[a]);if(a==b)return a;REP(i,15,0) {if(fa[a][i]!=fa[b][i]) {a=fa[a][i],b=fa[b][i];}}return fa[a][0];
}
void Do() {cin>>q;int a,b;while(q--) {scanf("%d%d",&a,&b);if(Tree[a]!=Tree[b])puts("-1");else {int lca=LCA(a,b);int step=dep[a]-dep[lca];int ans=1e9;FOR(i,0,15) {if(step&(1<<i)) {if(Mi[a][i]<ans)ans=Mi[a][i];a=fa[a][i];}}step=dep[b]-dep[lca];FOR(i,0,15) {if(step&(1<<i)) {if(Mi[b][i]<ans)ans=Mi[b][i];b=fa[b][i];}}printf("%d\n",ans);}}
}
void solve() {Init();//并查集预处理build();//建树Dfs();//遍历每个联通块Pre();//倍增的处理Do();//求答案
}
int main() {cin>>n>>m;FOR(i,1,m)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].cost);solve();return 0;
}

小结

这份卷不是特别难,我这种蒟蒻考也能AK······
也没什么要注意的地方。(希望今年的题目也都长这样ლ(╹◡╹ლ))

最新文章

  1. Java中多线程启动,为什么调用的是start方法,而不是run方法?
  2. python定制框架知识点_我的第一个python web开发框架(25)——定制ORM(一)
  3. redis linux 文件位置,Linux下Redis的安装和部署
  4. 素数 乘法表 闰年
  5. .net remoting 与webservice
  6. Android WebView与JS交互入门
  7. JAVA面试要点007---equals和==的区别小结
  8. C++STL之整理算法
  9. vs2017下载教程
  10. CSDN 上传资源已经存在
  11. 利用计算机开方洋葱数学,他借助“洋葱数学”实现学讲模式
  12. 生产计划:制定您的生产流程
  13. Linux内核固定虚拟地址映射
  14. [Azure DevOps] 如何安装并配置 Build Agent
  15. java 请求超时处理_android 网络请求超时简单处理(基于rxjava)
  16. Vue SSR 从入门到 Case Study
  17. Java工程师成神之路 | 2022正式版
  18. 烂泥:火车头采集器使用GAE代理
  19. 如何搭建卫星地图离线地图服务?
  20. 浏览器判断是否全屏, 设置浏览器全屏,设置浏览器退出全屏

热门文章

  1. 基于STM32F427的模拟SSI协议绝对式编码器位置反馈通信
  2. JAVA程序设计基础(第六版)第六章习题 6.13
  3. 一级计算机第65套题,全国计算机一级考试题库(附答案).pdf
  4. python解释器错误
  5. mysql执行SQL脚本
  6. 产品体系建模工具软件
  7. vuejs2和echarts3组合显示图表
  8. 一小时做出Java实战项目——飞翔的小鸟
  9. Java实战项目,附带源码+视频教程。
  10. mysql中主键数据类型_MySQL系列-详解mysql数据类型