重走长征路---OI每周刷题记录---10月27日 2013 AC 10题

总目录详见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<N<=1000,0<=X,Y<=1000,V>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 <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#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 <stdio.h>
#include <string.h>
#include <math.h>
#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 <stdio.h>
#include <string.h>
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<len;i++){
        j=secret[i]-'A';
        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<len;i++){
        j=secret[i]-'A';
        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 <stdio.h>
#include <string.h>
#include <stdlib.h>
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 <stdio.h>
#include <string.h>
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<ans2,之后的分析却完全没有章法 
//ans1=max(a0/b1,a0*a1/b2),ans2=max(a0/b2,a0*a2/b1)
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1<ans2成立 
//若ans1值为a0*a1/b2,必然大于a0/b2,要ans1<ans2成立,需 a0*a1/b2<a0*a2/b1,整理可得a1*b1<a2*b2 
//故需按a[i]*b[i]自小到大排序。 
//归根结底,数学相对来说,是短板,需加强学习研究。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 <cstring>//少了此句  
//看来,还是要在linux下编写才安全 
//修改,提交AC。2019-1-20 11:14
//编码能力有了较大的提高,一次成功。
//以下为AC代码
//此题最大的收获,在Dev-cpp中编写C++程序,少了关键的头文件都能通过,在NOIP比赛中可是要爆0的。

//马上在noi linux(ubuntu)下测试,将 #include <cstring> 注释

//g++中的情况

//GUIDE中的情况

//Windows中的Dev-cpp无论是高版本,还是低版本,以C++的形式编写代码,缺少头文件是不报错的。2019-1-20 14:36
#include <cstdio>
#include <algorithm>
#include <cstring>//少了此句 
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<b.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]<y[0])return -1;
    for(i=x[0];i>=1;i--)//x[0]==y[0]
        if(x[i]>y[i])return 1;
        else if(x[i]<y[i])return -1;
    return 0;
    
}
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<n;i++){
        mul(q[i].a,left);
        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<ans2,之后的分析却完全没有章法 
//ans1=max(a0/b1,a0*a1/b2),ans2=max(a0/b2,a0*a2/b1)
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1<ans2成立 
//若ans1值为a0*a1/b2,必然大于a0/b2,要ans1<ans2成立,需 a0*a1/b2<a0*a2/b1,整理可得a1*b1<a2*b2 
//故需按a[i]*b[i]自小到大排序。 
//归根结底,数学相对来说,是短板,需加强学习研究。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 <cstdio>
#include <algorithm>
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<b.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<n;i++)left*=q[i].a,gold[i+1]=left/q[i+1].b,ans=max(gold[i+1],ans);
    printf("%lld\n",ans);
    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<ans2,之后的分析却完全没有章法 
//ans1=max(a0/b1,a0*a1/b2),ans2=max(a0/b2,a0*a2/b1)
//若ans1值为a0/b1,必然小于a0*a2/b1,故ans1<ans2成立 
//若ans1值为a0*a1/b2,必然大于a0/b2,要ans1<ans2成立,需 a0*a1/b2<a0*a2/b1,整理可得a1*b1<a2*b2 
//故需按a[i]*b[i]自小到大排序。 
//归根结底,数学相对来说,是短板,需加强学习研究。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 <cstdio>
#include <algorithm>
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<b.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<n;i++)ans*=q[i].a;
    printf("%lld\n",ans/q[n].b);
    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 <stdio.h>
#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<b?a:b;
}
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<ans){//剪枝放在此处 d<ans
            vis[i]=1;
            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 <cstdio>
#include <algorithm>
#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<b?a:b;
}
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 <cstdio>
#include <algorithm>
#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 <cstdio>
#include <algorithm>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#include <string.h>
#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<w[k])last=w[k];
            break;
        }
    }
    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 <stdio.h>
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 <cstdio>
#include <cstring>
#include <algorithm>
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 <stdio.h>
#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 该周内容

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值