总目录详见https://blog.csdn.net/mrcrack/article/details/84471041
做题原则,找不到测评地址的题不做。2018-11-28
该周最大的收获:NOIP复赛 潜在的 爆0 情况
//Windows中的Dev-cpp无论是高版本,还是低版本,以C++的形式编写代码,缺少头文件是不报错的。2019-1-20 14:36
//若想深入了解,可学习 本文 国王游戏 编写的过程,
重走长征路---OI每周刷题记录---10月27日 2013
本周共计10题
测评地址:
spfa
1.竹子战争 //在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1301
dijstra
2.最短路径问题 //在线测评地址http://codevs.cn/problem/2602/
字符串
3.潜伏者 //在线测评地址https://www.luogu.org/problemnew/show/P1071
4.jam计数法 //在线测评地址https://www.luogu.org/problemnew/show/P1061
贪心
5.国王游戏 //在线测评地址https://www.luogu.org/problemnew/show/P1080
6.导弹拦截 //在线测评地址https://www.luogu.org/problemnew/show/P1158
模拟
7.接水问题 //在线测评地址https://www.luogu.org/problemnew/show/P1190
8.数字统计 //在线测评地址https://www.luogu.org/problemnew/show/P1179
9.三国游戏 //在线测评地址https://www.luogu.org/problemnew/show/P1199
10.多项式输出 //在线测评地址https://www.luogu.org/problemnew/show/P1067
题解:
1.竹子战争 spfa
//1301: 竹子战争
//在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1301
//帐号20180901
//因对于100%的数据 0
//果断采用Dijkstra算法,O(n^2),肯定能AC
//存储采用邻接矩阵方式,易编写
//该题对浮点数进行运算,最长距离sqrt((1000-0)^2+(1000-0)^2 )*999=1.414*10^6
//1000^2+1000^2=2*10^6,在根式中运算时,int不会溢出
//故INF采用1e10
//水平距离不超过R,高度差不超过D ,才有距离,否则距离INF
//程序编好,样例数据输出是1.500,反复阅读程序,没有问题啊
//无奈,将map[][]数据打印,再结合读题,发现,还是没有问题啊
//反复读题,发现,“所花的时间为两个顶点间的直线距离除以V”
//距离是算 三维的距离 sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(h1-h2)*(h1-h2));
//很快,样例通过,提交AC。2019-1-17 17:57
//该题难点,求的是 两个顶点间的直线 是 三维的。
#include
#include
#include
#include
#define maxn 1100
#define INF 1e10
int x[maxn],y[maxn],h[maxn],N,R,D,V,vis[maxn];
double map[maxn][maxn],d[maxn];
double dis1(int x1,int y1,int x2,int y2){//水平距离
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double dis2(int x1,int y1,int h1,int x2,int y2,int h2){//两个顶点间的直线距离
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(h1-h2)*(h1-h2));
}
int findMax(){
int i,k;
double min=INF;
for(i=1;i<=N;i++)
if(vis[i]==0&&min>=d[i])min=d[i],k=i;
return k;
}
void Dijkstra(){
int i,j,k;
memset(vis,0,sizeof(vis));
for(i=1;i<=N;i++)d[i]=map[1][i];
for(i=1;i<=N;i++){
k=findMax(),vis[k]=1;
for(j=1;j<=N;j++)
if(vis[j]==0&&d[j]>d[k]+map[k][j])
d[j]=d[k]+map[k][j];
}
if(fabs(d[N]-INF)<1e-6)printf("No Solution\n"); //因为是浮点数,== 不好用了。只能采用 fabs(d[N]-INF)<1e-6
else printf("%.3lf\n",d[N]/V);
}
int main(){
int i,j;
scanf("%d%d%d%d",&N,&R,&D,&V);
for(i=1;i<=N;i++)scanf("%d%d%d",&x[i],&y[i],&h[i]);
for(i=1;i<=N;i++)//初始化
for(j=1;j<=N;j++)
if(i==j)map[i][j]=0;
else if(abs(h[i]-h[j])<=D&&dis1(x[i],y[i],x[j],y[j])<=R){
map[i][j]=dis2(x[i],y[i],h[i],x[j],y[j],h[j]);
}else map[i][j]=INF;
Dijkstra();
return 0;
}
dijstra
2.最短路径问题
//2602 最短路径问题
//在线测评地址http://codevs.cn/problem/2602/
//因n<=100,果断采用Floyd算法。
//点间距离最大值(10000-(-10000))^2+(10000-(-10000))^2=8*10^8 int不会溢出
//两点间最长距离99*8*10^8=8*10^10 int溢出,需采用long long
//采用邻接矩阵的方式存储
//最大值,若超出了int ,如何表示呢?
//重新看了题目,发现距离发生在 浮点数 范畴,上面的想法 多虑了。
//点间距离最大值sqrt((10000-(-10000))^2+(10000-(-10000))^2)=sqrt(8*10^8)=3*10^4
//两点间最大距离99*3*10^4=3*10^6
//样例通过,提交AC。2019-1-16 20:08
//该题比较特别的地方,是Floyd算法中进行的是浮点数的运算。
#include
#include
#include
#define maxn 110
#define LL long long
#define INF 1e10
int x[maxn],y[maxn];
double map[maxn][maxn];
double dis(int x1,int y1,int x2,int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main(){
int n,m,s,t,i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)map[i][j]=0;
else map[i][j]=INF;
for(i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
scanf("%d",&m);
while(m--){
scanf("%d%d",&i,&j);
map[j][i]=map[i][j]=dis(x[i],y[i],x[j],y[j]);
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(map[i][j]>map[i][k]+map[k][j])
map[i][j]=map[i][k]+map[k][j];
scanf("%d%d",&s,&t);
printf("%.2lf\n",map[s][t]);
return 0;
}
字符串
3.潜伏者
//P1071 潜伏者
//NOIP 2009 提高组
//在线测评地址https://www.luogu.org/problemnew/show/P1071
//源码,密码 一一对应
//源码->密码 开一个数组,密码->源码 再开一个数组,这样可以方便查重
//样例2比较奇特,字母‘Z’在原信息中没有出现,输出“Failed”。
//原以为,将现在的密码破解即可,而非需要知道所有字母 密码。
//读题发现,1. 所有信息扫描完毕,‘A’-‘Z’ 所有26个字母在原信息中均出现过并获得了相应的“密字”
//3个样例通过,提交AC。2019-1-17
#include
#include
int a[30],b[30];//a[k]=j k源码 j密码,b[j]=k k源码 j密码
char source[110],secret[110];
int main(){
int i,j,k,len;
memset(a,-1,sizeof(a)),memset(b,-1,sizeof(b));
scanf("%s%s",secret,source);
len=strlen(secret);
for(i=0;i
k=source[i]-'A';
if(a[k]==-1)a[k]=j;
else if(a[k]!=j){//出现,一个源码 对应 多个密码
printf("Failed\n");
return 0;
}
if(b[j]==-1)b[j]=k;
else if(b[j]!=k){//出现,一个密码 对应 多个源码
printf("Failed\n");
return 0;
}
}
for(j=0;j<26;j++)//漏了此循环对应的功能。
if(b[j]==-1){//1. 所有信息扫描完毕,‘A’-‘Z’ 所有26个字母在原信息中均出现过并获得了相应的“密字”
printf("Failed\n");
return 0;
}
scanf("%s",secret);
len=strlen(secret);
for(i=0;i
source[i]='A'+b[j];
}
source[len]='\0';
printf("%s\n",source);
return 0;
}
4.jam计数法
//P1061 Jam的计数法
//NOIP 普及组 2006
//在线测评地址https://www.luogu.org/problemnew/show/P1061
//题目,花了一定的时间,精力,看懂了
//一个大胆想法冒出来,求出所有排列数,按字典序排序
//但一想,容易超时
//再看题目要求,输出前5个即可,
//那么深搜+回溯,很快能解决该题。
//问题是,如何结束程序,难道要用exit(0);吗
//该题的难点是,如何找到第一个答案。2019-1-8 21:15
//样例通过,但测试了一下,TLE是免不了的,估计得分在50左右。
//提交,AC,100分,不敢相信自己的眼睛,这数据也太水了吧。2019-1-9 17:19
//仔细想了想,因字符自左到右递增,无需回溯,深搜即可,修改代码,提交AC。2019-1-9 20:45
#include
#include
#include
int s,t,w,a[30],b[30],k=0,cnt=0;
char jam[30];
void dfs(int step){
int i,j;
if(step==w+1){
if(k==0){
for(j=1;j<=w;j++)
if(a[j]!=b[j])
break;
if(j==w+1)k=1;
}
if(k==1){
cnt++;
if(cnt>1){
for(j=1;j<=w;j++)printf("%c",b[j]-1+'a');
printf("\n");
}
if(cnt==6)exit(0);//推出程序
}
return;
}
for(i=b[step-1]+1;i<=t;i++){
b[step]=i;
dfs(step+1);
}
}
int main(){
int i,len;
scanf("%d%d%d%s",&s,&t,&w,jam+1);
len=strlen(jam+1);
for(i=1;i<=len;i++)a[i]=jam[i]-'a'+1;
b[0]=a[1]-1;
dfs(1);
return 0;
}
//P1061 Jam的计数法
//NOIP 普及组 2006
//在线测评地址https://www.luogu.org/problemnew/show/P1061
//以下算法,是梦想中的算法,终于实现了
//出自https://www.cnblogs.com/YXY-1211/p/5073808.html
//高兴之情,难于用言语表达
//算法的时间复杂度基本上是O(n)
//测试了,发现,不再惧怕超时,无惧任何测试数据。
//样例通过,提交AC。2019-1-9 21:03
#include
#include
int s,t,w;
char jam[30];
int main(){
int i,j,k;
scanf("%d%d%d%s",&s,&t,&w,jam+1);
t='a'+t-1;//数字转字符
for(i=1;i<=5;i++){
j=w;//个位
while(j>=1&&jam[j]==t+j-w)j--;//若当前位已达到最大值,不可加
if(j==0)break;//所有位都达到了最大位
jam[j]++;//当前位,进位
for(k=j+1;k<=w;k++)jam[k]=jam[k-1]+1;//之后的每位,都在前一位的基础上+1,已是最小值
printf("%s",jam+1);
printf("\n");
}
return 0;
}
贪心
5.国王游戏
//P1080 国王游戏
//在线测评地址https://www.luogu.org/problemnew/show/P1080
//简单模拟样例,感觉,金币最多的是最后一个
//n=10,10!=3628800,n=20,20!=2432902008176640000,深搜dfs只能得20分。暂不考虑
//仔细想了想一般做法,感觉把握不大,那么回到深搜dfs,配上剪枝,估计能到30分
//int是否溢出,7^20=79792266297612001
//long long 2^63=9223372036854775808
//需上 long long ,深搜dfs+回溯,配合剪枝
//样例通过,提交20分,测试点2,4-10TLE。好吧,题目没有给一点机会。2019-1-19 17:06
//深搜dfs程序优点,可以与之后的其它算法程序对拍,验证,其它算法程序的正确性。
//以下为20分代码。
//该题出得不错,言简意赅,难在于思考
//研究过程中,发现只关注a[i]或是b[i],是不行的,需同时关注
//因n<=10000,需采用O(nlogn)算法
//a,b是整数,最小值为1
//很想看解答,但是忍住了。
//反复求证,无果,翻看解答https://www.luogu.org/problemnew/solution/P1080
//一步之遥,确实难以跨越的,自个分析到了如果ans1
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1
//归根结底,数学相对来说,是短板,需加强学习研究。2019-1-20 9:09
//a[i]*b[i]最大值10^8
//求和a[1]*a[2]*...*a[n-1]最大值是(10^4)^(10^4)=10^40000 需上高精度算法
//该题,可考虑long long,拿部分分
//采用C++中的sort函数,排序
//突然发现,得用上结构体。
//最多赏金,发生在最后一个大臣。
//考试中会选择高精度算法吗,如果水平很高,会
//long long的算法也会编,慎重起见,该题,会对拍。
//对拍的同时编写下一题。根据对拍的情况,决定提交的代码。
//提交50分,测试点2,6,8-10WA,怎么可能这么点,重新读题,发现
//将n的最大值1000看成了10000,
//以下为50分代码2019-1-20 10:12
//仔细想了想,最多赏金,未必出现在最后一个大臣。ans1,ans2只是当前两个大臣的抉择
//提交60分,基本满意,2019-1-20 10:26
//以下为60分代码
//开始高精度算法的编写
//第一步,高精度乘法,好在是高精度*int
//第二步,高精度除法,
//提交Compile Error,考试中可是要爆0,奇怪编译器怎么不报错
//#include
//看来,还是要在linux下编写才安全
//修改,提交AC。2019-1-20 11:14
//编码能力有了较大的提高,一次成功。
//以下为AC代码
//此题最大的收获,在Dev-cpp中编写C++程序,少了关键的头文件都能通过,在NOIP比赛中可是要爆0的。
//马上在noi linux(ubuntu)下测试,将 #include
//g++中的情况
//GUIDE中的情况
//Windows中的Dev-cpp无论是高版本,还是低版本,以C++的形式编写代码,缺少头文件是不报错的。2019-1-20 14:36
#include
#include
#include
using namespace std;
#define LL long long
#define maxn 1100
int n,left[4100],gold[4100],ans[4100];
struct node{
int a,b,c;
}q[maxn];
int cmp(const struct node &a,const struct node &b){
return a.c
void mul(int x,int* y){//高精度*int
int i;
for(i=1;i<=y[0];i++)y[i]*=x;
for(i=1;i<=y[0];i++){
y[i+1]+=y[i]/10;
y[i]%=10;
}
if(y[i]==0)return;
while(y[i]>=10)y[i+1]+=y[i]/10,y[i]%=10,i++;
y[0]=i;
}
void divide(int x,int *y,int *z){//高精度/int
int i,d=0;
//memset(z,0,sizeof(z));//此句写得不好
z[0]=y[0];
for(i=y[0];i>=1;i--){
d*=10;
d+=y[i];
z[i]=d/x;
d%=x;
}
i=z[0];
while(z[i]==0)i--;
z[0]=i;
}
int compare(int *x,int *y){//返回1,x大于y,返回0 x等于y,返回-1, x小于y
int i;
if(x[0]>y[0])return 1;
if(x[0]
if(x[i]>y[i])return 1;
else if(x[i]
}
int main(){
int i;
scanf("%d",&n);
for(i=0;i<=n;i++)scanf("%d%d",&q[i].a,&q[i].b),q[i].c=q[i].a*q[i].b;
sort(q+1,q+1+n,cmp);
memset(left,0,sizeof(left)),left[0]=1,left[1]=1;
memset(ans,0,sizeof(ans)),ans[0]=1,ans[0]=1;
for(i=0;i
memset(gold,0,sizeof(gold));
divide(q[i+1].b,left,gold);
if(compare(gold,ans)==1)memcpy(ans,gold,sizeof(gold));
}
for(i=ans[0];i>=1;i--)printf("%d",ans[i]);
return 0;
}
//P1080 国王游戏
//在线测评地址https://www.luogu.org/problemnew/show/P1080
//简单模拟样例,感觉,金币最多的是最后一个
//n=10,10!=3628800,n=20,20!=2432902008176640000,深搜dfs只能得20分。暂不考虑
//仔细想了想一般做法,感觉把握不大,那么回到深搜dfs,配上剪枝,估计能到30分
//int是否溢出,7^20=79792266297612001
//long long 2^63=9223372036854775808
//需上 long long ,深搜dfs+回溯,配合剪枝
//样例通过,提交20分,测试点2,4-10TLE。好吧,题目没有给一点机会。2019-1-19 17:06
//深搜dfs程序优点,可以与之后的其它算法程序对拍,验证,其它算法程序的正确性。
//以下为20分代码。
//该题出得不错,言简意赅,难在于思考
//研究过程中,发现只关注a[i]或是b[i],是不行的,需同时关注
//因n<=10000,需采用O(nlogn)算法
//a,b是整数,最小值为1
//很想看解答,但是忍住了。
//反复求证,无果,翻看解答https://www.luogu.org/problemnew/solution/P1080
//一步之遥,确实难以跨越的,自个分析到了如果ans1
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1
//归根结底,数学相对来说,是短板,需加强学习研究。2019-1-20 9:09
//a[i]*b[i]最大值10^8
//求和a[1]*a[2]*...*a[n-1]最大值是(10^4)^(10^4)=10^40000 需上高精度算法
//该题,可考虑long long,拿部分分
//采用C++中的sort函数,排序
//突然发现,得用上结构体。
//最多赏金,发生在最后一个大臣。
//考试中会选择高精度算法吗,如果水平很高,会
//long long的算法也会编,慎重起见,该题,会对拍。
//对拍的同时编写下一题。根据对拍的情况,决定提交的代码。
//提交50分,测试点2,6,8-10WA,怎么可能这么点,重新读题,发现
//将n的最大值1000看成了10000,
//以下为50分代码2019-1-20 10:12
//仔细想了想,最多赏金,未必出现在最后一个大臣。ans1,ans2只是当前两个大臣的抉择
//提交60分,基本满意,2019-1-20 10:26
//以下为60分代码
#include
#include
using namespace std;
#define LL long long
#define maxn 1100
int n;
LL gold[maxn];
struct node{
int a,b,c;
}q[maxn];
int cmp(const struct node &a,const struct node &b){
return a.c
LL max(LL a,LL b){
return a>b?a:b;
}
int main(){
int i;
LL left=1,ans=-1;
scanf("%d",&n);
for(i=0;i<=n;i++)scanf("%d%d",&q[i].a,&q[i].b),q[i].c=q[i].a*q[i].b;
sort(q+1,q+1+n,cmp);
for(i=0;i
return 0;
}
//P1080 国王游戏
//在线测评地址https://www.luogu.org/problemnew/show/P1080
//简单模拟样例,感觉,金币最多的是最后一个
//n=10,10!=3628800,n=20,20!=2432902008176640000,深搜dfs只能得20分。暂不考虑
//仔细想了想一般做法,感觉把握不大,那么回到深搜dfs,配上剪枝,估计能到30分
//int是否溢出,7^20=79792266297612001
//long long 2^63=9223372036854775808
//需上 long long ,深搜dfs+回溯,配合剪枝
//样例通过,提交20分,测试点2,4-10TLE。好吧,题目没有给一点机会。2019-1-19 17:06
//深搜dfs程序优点,可以与之后的其它算法程序对拍,验证,其它算法程序的正确性。
//以下为20分代码。
//该题出得不错,言简意赅,难在于思考
//研究过程中,发现只关注a[i]或是b[i],是不行的,需同时关注
//因n<=10000,需采用O(nlogn)算法
//a,b是整数,最小值为1
//很想看解答,但是忍住了。
//反复求证,无果,翻看解答https://www.luogu.org/problemnew/solution/P1080
//一步之遥,确实难以跨越的,自个分析到了如果ans1
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1
//归根结底,数学相对来说,是短板,需加强学习研究。2019-1-20 9:09
//a[i]*b[i]最大值10^8
//求和a[1]*a[2]*...*a[n-1]最大值是(10^4)^(10^4)=10^40000 需上高精度算法
//该题,可考虑long long,拿部分分
//采用C++中的sort函数,排序
//突然发现,得用上结构体。
//最多赏金,发生在最后一个大臣。
//考试中会选择高精度算法吗,如果水平很高,会
//long long的算法也会编,慎重起见,该题,会对拍。
//对拍的同时编写下一题。根据对拍的情况,决定提交的代码。
//提交50分,测试点2,6,8-10WA,怎么可能这么点,重新读题,发现
//将n的最大值1000看成了10000,
//以下为50分代码2019-1-20 10:12
#include
#include
using namespace std;
#define LL long long
#define maxn 1100
int n;
struct node{
int a,b,c;
}q[maxn];
int cmp(const struct node &a,const struct node &b){
return a.c
int main(){
int i;
LL ans=1;
scanf("%d",&n);
for(i=0;i<=n;i++)scanf("%d%d",&q[i].a,&q[i].b),q[i].c=q[i].a*q[i].b;
sort(q+1,q+1+n,cmp);
for(i=0;i
return 0;
}
//P1080 国王游戏
//在线测评地址https://www.luogu.org/problemnew/show/P1080
//简单模拟样例,感觉,金币最多的是最后一个
//n=10,10!=3628800,n=20,20!=2432902008176640000,深搜dfs只能得20分。暂不考虑
//仔细想了想一般做法,感觉把握不大,那么回到深搜dfs,配上剪枝,估计能到30分
//int是否溢出,7^20=79792266297612001
//long long 2^63=9223372036854775808
//需上 long long ,深搜dfs+回溯,配合剪枝
//样例通过,提交20分,测试点2,4-10TLE。好吧,题目没有给一点机会。2019-1-19 17:06
//深搜dfs程序优点,可以与之后的其它算法程序对拍,验证,其它算法程序的正确性。
//以下为20分代码。
#include
#define LL long long
#define maxn 1100
#define INF 1e18
int a[maxn],b[maxn],n,vis[maxn],g[maxn];
LL ans=INF;
LL min(LL a,LL b){
return a }
LL max(LL a,LL b){
return a>b?a:b;
}
void dfs(int step,LL c,LL d){
int i;
if(step==n+1){
ans=min(ans,d);
return ;
}
for(i=1;i<=n;i++)
if(vis[i]==0&&d
dfs(step+1,c*a[i],max(c/b[i],d));//此处写成 dfs(step,c*a[i],max(c/b[i],d)); 也是昏了//d表示,到达i大臣时,获得的金币的大臣获得最多金币数量
vis[i]=0;//回溯
}
}
int main(){
int i;
scanf("%d",&n);
for(i=0;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
dfs(1,a[0],-1);//此处写成 dfs(a[0],1,INF); 昏到家了
printf("%lld\n",ans);
return 0;
}
6.导弹拦截
//P1158 导弹拦截
//NOIP 普及组 2010
//在线测评地址https://www.luogu.org/problemnew/show/P1158
//题目出得不错,至少样例解释得非常清楚
//通过样例,理解了题意。
//计算一颗导弹离两个拦截系统的距离,选取最小值,确定该枚导弹归属的拦截系统
//在第一套拦截系统里找出最大值,在第二套拦截系统里找出最大值
//计算最小代价。
//距离最大值(1000-(-1000))^2+(1000-(-1000))^2=8*10^6
//为了方便计算,不再开根号。
//该题感觉比较简单,纯模拟的题目。算法的时间复杂度O(n)。
//样例1,2通过,提交,30分,测试点1-2,5,7-10WA,不敢相信。2019-1-10 17:29
//仔细想了想,在每一次的选择过程中,只是考虑r1或是r2,而未通盘考虑r1+r2,估计问题出在这
//以下是30分代码,提醒读者,不要将问题想得简单化了。
//仔细想想,算法确实有问题,如下例子
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//样例通过,提交60分,测试点2,7,9,10WA,还算满意。2019-1-10 20:34
//还有什么地方没考虑到吗?
//以下为60分代码。
//想了想,还是有反例,以下为60分代码,运算过程
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//d1=11,d2=12 r1=11,r2=9
//而实际操作,对d1按自大到小排序,再处理
//d1=11,d2=12 r1=11,r2=0
//d1=10,d2=9 r1=11,r2=0
//d1=7,d2=8 r1=11,r2=0
//马上按上述算法修改代码
//该题有3个思维层次,30分,60分,100分,详见三处代码
//采用C++里的sort函数
//编写过程中,问题百出,不过,很快解决了。
//样例通过,提交70分,测试点7,9,10WA,真是服了。
//以下为70分代码。2019-1-10 21:13
//仔细想想,应该算两次,应该让两套系统都有机会 由大到小 操作一次。
//真是服了,又回到60分,测试点2,7,9,10WA,仔细一看,代码写昏了
//ans=ans>(r1+r2)?(r1+r2):ans;//取最小值,此句写成 ans=ans>(r1+r2)?ans:(r1+r2);
//提交90分,测试点10WA。2019-1-10 21:26
//以下为90分代码。将90分代码在http://codevs.cn/problem/1128/
//里提交,90分,错了测试点9,看来洛谷没将数据加强。2019-1-10 21:44
//看了https://www.luogu.org/problemnew/solution/P1158的作者: 皮皮鳝 更新时间: 2018-08-21 17:35题解才发现
//还是需要,实时判定r1+r2
//加上https://blog.csdn.net/qq_25978793/article/details/47703273此文的讲解,弄明白了。
//对r2的处理,有些绕,但还是弄明白了。2019-1-11
//样例通过,提交AC。
#include
#include
#define maxn 100100
#define INF 999999999
using namespace std;
int n;
struct node{
int x,y,d1,d2;
}q[maxn];
int dis(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int cmp1(const struct node &a,const struct node &b){
return a.d1>b.d1;
}
int min(int a,int b){
return a }
int max(int a,int b){
return a>b?a:b;
}
int main(){
int x1,y1,x2,y2,i,r2,d1,d2,ans;//r1=0,r2=0初始化很关键,其它值不行
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&q[i].x,&q[i].y);
q[i].d1=dis(q[i].x,q[i].y,x1,y1);
q[i].d2=dis(q[i].x,q[i].y,x2,y2);
}
sort(q+1,q+1+n,cmp1);//第1套系统,自大到小排序
ans=INF,r2=0;//因第一枚导弹已被第一套拦截系统拦截,故r2=0.
for(i=1;i<=n;i++){
ans=min(ans,q[i].d1+r2);//整个拦截过程中,最大的r2
r2=max(q[i].d2,r2);//上一枚导弹,会影响下一枚导弹对第2套拦截系统的拦截。
}
printf("%d\n",ans);
return 0;
}
//P1158 导弹拦截
//NOIP 普及组 2010
//在线测评地址https://www.luogu.org/problemnew/show/P1158
//题目出得不错,至少样例解释得非常清楚
//通过样例,理解了题意。
//计算一颗导弹离两个拦截系统的距离,选取最小值,确定该枚导弹归属的拦截系统
//在第一套拦截系统里找出最大值,在第二套拦截系统里找出最大值
//计算最小代价。
//距离最大值(1000-(-1000))^2+(1000-(-1000))^2=8*10^6
//为了方便计算,不再开根号。
//该题感觉比较简单,纯模拟的题目。算法的时间复杂度O(n)。
//样例1,2通过,提交,30分,测试点1-2,5,7-10WA,不敢相信。2019-1-10 17:29
//仔细想了想,在每一次的选择过程中,只是考虑r1或是r2,而未通盘考虑r1+r2,估计问题出在这
//以下是30分代码,提醒读者,不要将问题想得简单化了。
//仔细想想,算法确实有问题,如下例子
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//样例通过,提交60分,测试点2,7,9,10WA,还算满意。2019-1-10 20:34
//还有什么地方没考虑到吗?
//以下为60分代码。
//想了想,还是有反例,以下为60分代码,运算过程
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//d1=11,d2=12 r1=11,r2=9
//而实际操作,对d1按自大到小排序,再处理
//d1=11,d2=12 r1=11,r2=0
//d1=10,d2=9 r1=11,r2=0
//d1=7,d2=8 r1=11,r2=0
//马上按上述算法修改代码
//该题有3个思维层次,30分,60分,100分,详见三处代码
//采用C++里的sort函数
//编写过程中,问题百出,不过,很快解决了。
//样例通过,提交70分,测试点7,9,10WA,真是服了。
//以下为70分代码。2019-1-10 21:13
//仔细想想,应该算两次,应该让两套系统都有机会 由大到小 操作一次。
//真是服了,又回到60分,测试点2,7,9,10WA,仔细一看,代码写昏了
//ans=ans>(r1+r2)?(r1+r2):ans;//取最小值,此句写成 ans=ans>(r1+r2)?ans:(r1+r2);
//提交90分,测试点10WA。2019-1-10 21:26
//以下为90分代码。将90分代码在http://codevs.cn/problem/1128/
//里提交,90分,错了测试点9,看来洛谷没将数据加强。2019-1-10 21:44
#include
#include
#define maxn 100100
using namespace std;
int n;
struct node{
int x,y,d1,d2;
}q[maxn];
int dis(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int cmp1(const struct node &a,const struct node &b){
return a.d1>b.d1;
}
int cmp2(const struct node &a,const struct node &b){
return a.d2>b.d2;
}
int main(){
int x1,y1,x2,y2,i,r1=0,r2=0,d1,d2,ans;//r1=0,r2=0初始化很关键,其它值不行
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&q[i].x,&q[i].y);
q[i].d1=dis(q[i].x,q[i].y,x1,y1);
q[i].d2=dis(q[i].x,q[i].y,x2,y2);
}
sort(q+1,q+1+n,cmp1);//第1套系统,自大到小排序
for(i=1;i<=n;i++){
d1=q[i].d1,d2=q[i].d2;
if(r1>=d1||r2>=d2)continue;//已在打击范围
else{//替换r1,还是r2,目标是使r1+r2总代价最小
if(d1+r2>r1+d2)r2=d2;
else r1=d1;//猜测此处有问题
}
}
ans=r1+r2;
r1=r2=0;//初始化别忘了
sort(q+1,q+1+n,cmp2);//第2套系统,自大到小排序
for(i=1;i<=n;i++){
d1=q[i].d1,d2=q[i].d2;
if(r1>=d1||r2>=d2)continue;//已在打击范围
else{//替换r1,还是r2,目标是使r1+r2总代价最小
if(d1+r2>r1+d2)r2=d2;
else r1=d1;//猜测此处有问题
}
}
ans=ans>(r1+r2)?(r1+r2):ans;//取最小值,此句写成 ans=ans>(r1+r2)?ans:(r1+r2);
printf("%d\n",ans);
return 0;
}
//P1158 导弹拦截
//NOIP 普及组 2010
//在线测评地址https://www.luogu.org/problemnew/show/P1158
//题目出得不错,至少样例解释得非常清楚
//通过样例,理解了题意。
//计算一颗导弹离两个拦截系统的距离,选取最小值,确定该枚导弹归属的拦截系统
//在第一套拦截系统里找出最大值,在第二套拦截系统里找出最大值
//计算最小代价。
//距离最大值(1000-(-1000))^2+(1000-(-1000))^2=8*10^6
//为了方便计算,不再开根号。
//该题感觉比较简单,纯模拟的题目。算法的时间复杂度O(n)。
//样例1,2通过,提交,30分,测试点1-2,5,7-10WA,不敢相信。2019-1-10 17:29
//仔细想了想,在每一次的选择过程中,只是考虑r1或是r2,而未通盘考虑r1+r2,估计问题出在这
//以下是30分代码,提醒读者,不要将问题想得简单化了。
//仔细想想,算法确实有问题,如下例子
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//样例通过,提交60分,测试点2,7,9,10WA,还算满意。2019-1-10 20:34
//还有什么地方没考虑到吗?
//以下为60分代码。
//想了想,还是有反例,以下为60分代码,运算过程
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//d1=11,d2=12 r1=11,r2=9
//而实际操作,对d1按自大到小排序,再处理
//d1=11,d2=12 r1=11,r2=0
//d1=10,d2=9 r1=11,r2=0
//d1=7,d2=8 r1=11,r2=0
//马上按上述算法修改代码
//该题有3个思维层次,30分,60分,100分,详见三处代码
//采用C++里的sort函数
//编写过程中,问题百出,不过,很快解决了。
//样例通过,提交70分,测试点7,9,10WA,真是服了。
//以下为70分代码。2019-1-10 21:13
#include
#include
#define maxn 100100
using namespace std;
int n;
struct node{
int x,y,d1;
}q[maxn];
int dis(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int cmp(const struct node &a,const struct node &b){
return a.d1>b.d1;
}
int main(){
int x1,y1,x2,y2,i,r1=0,r2=0,d1,d2;//r1=0,r2=0初始化很关键,其它值不行
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&q[i].x,&q[i].y);
q[i].d1=dis(q[i].x,q[i].y,x1,y1);
}
sort(q+1,q+1+n,cmp);
for(i=1;i<=n;i++){
d1=q[i].d1,d2=dis(q[i].x,q[i].y,x2,y2);
if(r1>=d1||r2>=d2)continue;//已在打击范围
else{//替换r1,还是r2,目标是使r1+r2总代价最小
if(d1+r2>r1+d2)r2=d2;
else r1=d1;
}
}
printf("%d\n",r1+r2);
return 0;
}
//P1158 导弹拦截
//NOIP 普及组 2010
//在线测评地址https://www.luogu.org/problemnew/show/P1158
//题目出得不错,至少样例解释得非常清楚
//通过样例,理解了题意。
//计算一颗导弹离两个拦截系统的距离,选取最小值,确定该枚导弹归属的拦截系统
//在第一套拦截系统里找出最大值,在第二套拦截系统里找出最大值
//计算最小代价。
//距离最大值(1000-(-1000))^2+(1000-(-1000))^2=8*10^6
//为了方便计算,不再开根号。
//该题感觉比较简单,纯模拟的题目。算法的时间复杂度O(n)。
//样例1,2通过,提交,30分,测试点1-2,5,7-10WA,不敢相信。2019-1-10 17:29
//仔细想了想,在每一次的选择过程中,只是考虑r1或是r2,而未通盘考虑r1+r2,估计问题出在这
//以下是30分代码,提醒读者,不要将问题想得简单化了。
//仔细想想,算法确实有问题,如下例子
//d1=10,d2=9 r1=0,r2=9
//d1=7,d2=8 r1=0,r2=9
//样例通过,提交60分,测试点2,7,9,10WA,还算满意。2019-1-10 20:34
//还有什么地方没考虑到吗?
//以下为60分代码。
#include
#define maxn 100100
int x[maxn],y[maxn],n;
int dis(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int main(){
int x1,y1,x2,y2,i,d1,d2,r1=0,r2=0;//r1=0,r2=0初始化很关键,其它值不行
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&x[i],&y[i]);
d1=dis(x[i],y[i],x1,y1),d2=dis(x[i],y[i],x2,y2);
if(r1>=d1||r2>=d2)continue;//已在打击范围
else{//替换r1,还是r2,目标是使r1+r2总代价最小
if(d1+r2>r1+d2)r2=d2;
else r1=d1;
}
}
printf("%d\n",r1+r2);
return 0;
}
//P1158 导弹拦截
//NOIP 普及组 2010
//在线测评地址https://www.luogu.org/problemnew/show/P1158
//题目出得不错,至少样例解释得非常清楚
//通过样例,理解了题意。
//计算一颗导弹离两个拦截系统的距离,选取最小值,确定该枚导弹归属的拦截系统
//在第一套拦截系统里找出最大值,在第二套拦截系统里找出最大值
//计算最小代价。
//距离最大值(1000-(-1000))^2+(1000-(-1000))^2=8*10^6
//为了方便计算,不再开根号。
//该题感觉比较简单,纯模拟的题目。算法的时间复杂度O(n)。
//样例1,2通过,提交,30分,测试点1-2,5,7-10WA,不敢相信。2019-1-10 17:29
//仔细想了想,在每一次的选择过程中,只是考虑r1或是r2,而未通盘考虑r1+r2,估计问题出在这
//以下是30分代码,提醒读者,不要将问题想得简单化了。
#include
#define maxn 100100
int x[maxn],y[maxn],z[maxn],r[maxn],n;//z[i]归属,第1套,还是第2套
int dis(int x1,int y1,int x2,int y2){
return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
}
int max(int a,int b){
return a>b?a:b;
}
int main(){
int x1,y1,x2,y2,i,d1,d2,r1=-1,r2=-2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&x[i],&y[i]);
d1=dis(x[i],y[i],x1,y1),d2=dis(x[i],y[i],x2,y2);
if(d1>d2)z[i]=2,r[i]=d2;
else z[i]=1,r[i]=d1;
}
for(i=1;i<=n;i++)
if(z[i]==1)r1=max(r1,r[i]);
else r2=max(r2,r[i]);
printf("%d\n",r1+r2);
return 0;
}
模拟
7.接水问题
//P1190 接水问题
//NOIP 2010 普及组
//在线测评地址https://www.luogu.org/problemnew/show/P1190
//最长时间10000*100=10^6,故纯模拟方式处理此题
//放心,因累计时间最长10^6,故两重循环不会超时
//#define maxn 10200理由是,按算法,可能用到10001-10100的节点,故再开大一些
//样例通过,提交AC。2019-1-16 18:08
//感觉算法编得不错,完全模拟接水过程。
#include
#include
#define maxn 10200
int w[maxn];
int main(){
int n,m,i,j,k,flag,p,last;
memset(w,0,sizeof(w));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&w[i]);
p=m;
for(i=1;i<=1000100;i++){
flag=0;
for(j=1;j<=m;j++){
w[j]--;
if(w[j]==0){
p++;
if(p>n)flag=1;//没有人没接水
w[j]=w[p];//下一个k人,接上一个j人位置
}
}
if(flag){//所有人都在接水
last=w[1];
for(k=1;k<=m;k++)//找当前接水时间最长的
if(last
}
}
printf("%d\n",i+last);
return 0;
}
8.数字统计
//P1179 数字统计
//NOIP 2010 普及组
//在线测评地址https://www.luogu.org/problemnew/show/P1179
//算法的时间复杂度100000*6=6*10^5 100000解析共6个数字
//6*100000=6*10^5故int不会溢出
//该题算法,将一个整数解析成一个一个的数字
//样例通过,提交AC。2018-11-28
#include
int count(int n){
int ans=0;
while(n){
if(n%10==2)ans++;
n/=10;
}
return ans;
}
int main(){
int ans=0,i,L,R;
scanf("%d%d",&L,&R);
for(i=L;i<=R;i++)
ans+=count(i);
printf("%d\n",ans);
return 0;
}
9.三国游戏
//P1199 三国游戏
//NOIP 2010 普及组 第4题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1199
//0≤默契值≤1,000,000,000, 0≤默契值*2≤2,000,000,000 int 不会溢出
//N≤500,O(n^2)不会超时,但O(n^3)超时
//读入武将默契值,不放心,输出查看,正确后继续后面编写。
//空想是没有用的,直接上手,模拟了样例1,样例2。
//发现:按默契值自大到小排序,自大到小,要么被破坏,要么被选中,第一对被 人选中,人 获胜
//第一对被 计算机 选中,计算机 获胜
//感觉肯定能获胜。
//第一对的第一个肯定选不到,选第一对的第二个
//提交AC,太高兴了,思路独立想出,一次就AC了,思维的力量。2019-1-22
#include
#include
#include
using namespace std;
#define maxn 510
int N,b[maxn*maxn];
struct node{
int i,j,v;
}q[maxn*maxn];
int cmp(const struct node &a,const struct node &b){//自大到小
return a.v>b.v;
}
int main(){
int i,j,k,v,cnt=0;
memset(b,0,sizeof(b));
scanf("%d",&N);
memset(b,0,sizeof(b));
for(i=1;i<=N;i++)
for(j=i+1;j<=N;j++){
scanf("%d",&v);
cnt++;
q[cnt].i=i,q[cnt].j=j,q[cnt].v=v;
}
sort(q+1,q+cnt+1,cmp);
printf("1\n");
for(k=1;k<=cnt;k++){
i=q[k].i,j=q[k].j,v=q[k].v,b[i]++,b[j]++;//漏了此句 v=q[k].v
if(b[i]==2||b[j]==2){
printf("%d\n",v);
break;
}
}
return 0;
}
10.多项式输出
//P1067 多项式输出
//NOIP 2009 普及组 第1题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1067
//逻辑比较多,写成函数,这样条理清晰
//编好一个函数,测试一个,看看功能实现是否完备
//感谢出题者,样例给得不错,很多编写问题,在样例中能得到呈现。
//该题主要考察条件语句的使用。
//自个造了组数据
//输入
//5
//0 0 0 0 0 1
//输出
//1
//样例通过,提交50分,测试点3,7-10WA。
//仔细读题,发现an!=0,这个没注意到,换句话说,常数项可以为0
//第一项不可能为0,编写的时候想多了。上面造的数据明显就不对了
//发现n可以为0
//看了讨论区里的数据
//4
//1 1 1 1 1
//输出x^4+x^3+x^2+x+1
//再读题,发现,疏漏,如果x的指数为1,则接下来紧跟的指数部分形式为“x”
//考虑了x一次方的情况,提交AC.2019-1-21 21:07
//相信很多得50分的读者,卡在,漏考虑了x为一次方的情形,需特判。
//该题,难在需特判的地方比较多。
#include
#define maxn 110
int a[maxn],n;
void print_one(int x){//打印第一项
if(x==0)printf("%d",a[x]);
else{
if(a[x]==-1)printf("-");
else if(a[x]!=1)printf("%d",a[x]);//打印出的整数不带+号,打印出的负数带-号。
if(x==1)printf("x");//x==1的情况忽略了
else printf("x^%d",x);//非常数项
}
}
void print_other(int x){
if(x==0){//常数项处理
if(a[x]>0)printf("+%d",a[x]);
else printf("%d",a[x]);
}else{//非常数项
if(a[x]>0){//先打印系数
if(a[x]==1)printf("+");
else printf("+%d",a[x]);
}else{
if(a[x]==-1)printf("-");
else printf("%d",a[x]);
}
if(x==1)printf("x");
else printf("x^%d",x);//再打印 x的幂次项
}
}
int main(){
int i,k=0;
scanf("%d",&n);
for(i=n;i>=0;i--)scanf("%d",&a[i]);
for(i=n;i>=0;i--)
if(a[i]!=0){
k++;
if(k==1){//第一项
print_one(i);
}else{//非第一项
print_other(i);
}
}
return 0;
}
2019-1-22 AC 该周内容