重走长征路---OI每周刷题记录---11月4日 2013

总目录详见https://blog.csdn.net/mrcrack/article/details/84471041

做题原则,找不到测评地址的题不做。2018-11-28

重走长征路---OI每周刷题记录---11月4日  2013

本周共计22题

吐槽一下,该周不仅题目多,且不易。2019-1-29 07:55

测评地址:

dp

1.免费馅饼  //在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1142

2.石子合并  //在线测评地址https://www.luogu.org/problemnew/show/P1880

3.拦截导弹  //在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1407

4.能量项链  //在线测评地址https://www.luogu.org/problemnew/show/P1063

5.找雷  //在线测评地址https://www.luogu.org/problemnew/show/P2196

并查集

6.亲戚  //在线测评地址http://codevs.cn/problem/1073/

贪心

7.观光公交

heap

8.合并果子  //在线测评地址https://www.luogu.org/problemnew/show/P1090

模拟

9.寻宝  //在线测评地址https://www.luogu.org/problemnew/show/P1076

hash

10.方程的解数  //在线测评地址http://codevs.cn/problem/1735/ 

数论

11.数列  //在线测评地址https://www.luogu.org/problemnew/show/P1062

12.同余方程  //在线测评地址https://www.luogu.org/problemnew/show/P1082

13.多项式系数  //在线测评地址https://www.luogu.org/problemnew/show/P1313

dfs

14.选数  //在线测评地址https://www.luogu.org/problemnew/show/P1036

高精度

15.回文数  //在线测评地址https://www.luogu.org/problemnew/show/P1015

模拟

16.现在几点钟  //在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1063

17.选择客栈  //在线测评地址https://www.luogu.org/problemnew/show/P1311

18.机器翻译  //在线测评地址https://www.luogu.org/problemnew/show/P1540

19.计算器的改良  //在线测评地址https://www.luogu.org/problemnew/show/P1022

20.分数线划定  //在线测评地址https://www.luogu.org/problemnew/show/P1068

进制

21.进制转换  //在线测评地址https://www.luogu.org/problemnew/show/P1015

枚举

22.一元三次方程求解  //在线测评地址https://www.luogu.org/problemnew/show/P1024

题解:

dp

1.免费馅饼

//1142: 免费馅饼
//在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1142 
//看题,没什么思路,查找网络,此文https://blog.csdn.net/sbs2000/article/details/50670773给出思路 
//由于馅饼下落的时间和速度都不同,人只能向左右移动,馅饼只能向下移动。人和馅饼都同时移动,思考起来比较复杂,因此我们需要转变思路:
//算出每个时刻落到最底层的每个格子有多少分值的馅饼。
//如果将馅饼当成参照物,则馅饼向下落,可以看成馅饼不动,人往上走去摘取馅饼,这样人每1时刻都可以走到上一行的5个格子,
//这道题是经典动规模型数塔的变形,将馅饼落下的位置看做数塔中的列数,将下落的时间看做数塔中的行数,问题转化为求解从塔底到塔顶的最长路径。
//以上为摘抄内容,开始独立编写。a[i][j]第i秒到达底部的j列的馅饼分数值 
//该题考得比较全面,还需记录路径 
//切记,编好一部分功能,须及时进行测试。 
//分数值应该为非负,该题需进行说明。
//该题可能存在多解,不过题目未作说明,如何处理。
//编好,样例无法通过, 
//发现因需记录路径,无需再写max函数了 
//样例通过,重新读了代码,发现有冗余代码,删改, 
//提交,答案错误33% 
//重读题目,发现,时间最大值1000+100/1=1100,故[1100][110]需修改, 
//仔细想了想,有一个开始位置,有一个结束位置,开始位置没有考虑,可能不从0开始,开始误以为从0开始 
//修改,提交,答案错误50%。
//翻看http://hzwer.com/124.html代码,才发现,有些馅饼竟然可以接不到,真是没想到 
//修改,提交,答案错误50%。2019-1-25 21:42 
//发现数组a[][]未初始化,初始化后,提交,答案错误50%,2019-1-25 22:32
//突然间想到,既然有些馅饼接不到,那么有些时间段,也可以没有一块馅饼 
//故,代码的最大值是没有问题的,问题出在打印路径上。 
//打印路径需判定,上一层若无,仔细想了想,这个想法不对 
//反复读代码,读题,发现,代码写得有问题,中间时间就算没有馅饼了,人也可以做决策 
//begin变量造成该题的问题,时间应该是从0开始的。而非从begin开始。 
//修改,提交,答案错误33%。2019-1-25 22:52 
//无奈,将http://hzwer.com/124.html代码进行修改,不断靠近自己代码,每改动一点,提交AC,继续改动 
//终于发现自己代码问题,b=0;摆错位置,应该是在两重循环之内,而非两重循环之间
//修改,提交AC。2019-1-25 23:29 真不容易啊。 
#include
#include
int a[1200][110],W,H,b,p[1200][110];//p[i][j]=k记录路径,a[i][j]来自 a[i+1][k]
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    int i,j,start,h,d,v,pos,k,end=0;//pos起始位置 
    scanf("%d%d",&W,&H);
    memset(a,0,sizeof(a));//漏了此句 
    while(scanf("%d%d%d%d",&start,&h,&d,&v)!=EOF){
        if((H-1)%d==0){//漏了此举判断 
            end=max(end,start+(H-1)/d);
            a[start+(H-1)/d][h]+=v;
        }
    }
    for(i=end;i>=0;i--){//此处写成for(i=end;i>=begin-1;i--)//此处写成 for(i=t;i>=0;i--)
        //b=0;放在此处查了好久,花了2小时 
        for(j=1;j<=W;j++){
            b=0;//添加 ,花了2小时 
            if(j-2>=1&&b             if(j-1>=1&&b             if(b             if(j+1<=W&&b             if(j+2<=W&&b             a[i][j]+=b,p[i][j]=k;
        }
    }
    pos=(W+1)/2;
    printf("%d\n",a[0][pos]);
    for(i=0;i         printf("%d\n",p[i][pos]-pos);
        pos=p[i][pos];
    }
    return 0;
}

2.石子合并

//P1880 [NOI1995]石子合并
//在线测评地址https://www.luogu.org/problemnew/show/P1880 
//感觉要区分,顺时针,逆时针,但动笔研究,发现不影响结果 
//化圈为线,将N堆石子,变成N+N=2N堆石子即可,这样就可以在数组中直接处理
//先写最大得分。最小得分,照葫芦画瓢即可。 
//单个石子的最大值,最小值,没作说明,int是否溢出? 
//编到后面,突然发现,弄明白样例是关键 
//该题缺一个样例解释啊,突然感觉,样例没弄明白 
//4 5 9 4
// 9  9 4   9+
//  18  4   9+18
//    22    9+18+22=49
//
//4 5 9 4
// 9   13   9+13
//   22     9+13+22=44
//大致弄明白了
//突然想到要用前缀和,否则该题极难处理
//样例通过,提交AC。2019-1-26 20:17 
#include
#include
int n,a[210],dp1[210][210],dp2[210][210],sum[210];
int min(int a,int b){
    return a }
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    int i,j,k,p=999999999,q=-1;//p,q初始化,很重要。 
    memset(sum,0,sizeof(sum));
    scanf("%d",&n);
    memset(dp1,127,sizeof(dp1)),memset(dp2,0,sizeof(dp2));
    for(i=1;i<=2*n;i++)dp1[i][i]=0;//此行很关键 
    for(i=1;i<=n;i++)scanf("%d",&a[i]),a[n+i]=a[i];
    for(i=1;i<=2*n;i++)sum[i]+=sum[i-1]+a[i];
    for(k=1;k         for(i=1;i<=2*n;i++)//此处写成 for(i=1;i<=n;i++)
            for(j=i;j                 if(i+k<=2*n){//补上此功能
                    dp1[i][i+k]=min(dp1[i][i+k],dp1[i][j]+dp1[j+1][i+k]+sum[i+k]-sum[i-1]); 
                    dp2[i][i+k]=max(dp2[i][i+k],dp2[i][j]+dp2[j+1][i+k]+sum[i+k]-sum[i-1]);//此处写成 dp[i][i+k]=max(dp[i][i+k],dp[i][j]+dp[i+j+1][i+k]);
                }
    for(i=1;i<=n;i++){
        p=min(p,dp1[i][i+n-1]);
        q=max(q,dp2[i][i+n-1]);
    }
    printf("%d\n%d\n",p,q);
    return 0;
}

3.拦截导弹

//1407: 拦截导弹
//在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1407 
//该题的难点在于,n<=100000,O(n^2)算法无法AC 
//只能采用O(nlogn)算法 
//二分。
//样例通过,提交83%,答案错误,翻看之前的编码https://blog.csdn.net/mrcrack/article/details/84928209
//中的//P1020 导弹拦截
//仔细想想,原来的写法确实有问题,修改,提交AC。2019-1-17 21:02
//原来的写法,极端情况,二分在f[1],f[2]结束
//现在的写法,极端情况,在f[0],f[1]结束。 
#include
#define maxn 100100
int f[maxn],ans=0;//f[]是一个递减序列 
int main(){
    int n,h,i,left,right,mid;
    scanf("%d",&n);
    f[0]=100100;//飞行高度不高于10^5
    for(i=1;i<=n;i++){
        scanf("%d",&h);
        if(f[ans]>=h)ans++,f[ans]=h;//漏了此句 f[ans]=h
        else{
            left=0,right=ans;//此处写成left=1//此处left赋值很关键 
            while(left+1                 mid=(left+right)/2;
                if(f[mid]                 else left=mid;
            }
            f[right]=h;//此处写成f[left]=h; 
        }
    }
    printf("%d\n",ans);
    return 0;
}

4.能量项链

//P1063 能量项链
//NOIP 2006 提高组  第1题  共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1063 
//题目对样例解释得清清楚楚,出得好。 
//化圈为线,由N个珠子变成2*N个珠子,处理起来就方便了 
//题目连数据范围都说得很清楚,真是出得好。 
//并且说明了,顺逆时针。试了下 
//顺时针 
//1 2 3 4  (2,3)(3,5)(5,10)(10,2) 2*3*5+2*5*10+2*10*2=170
//2 3 4 1  (3,5)(5,10)(10,2)(2,3) 3*5*10+3*10*2+3*2*3=228
//3 4 1 2  (5,10)(10,2)(2,3)(3,5) 5*10*2+5*2*3+5*3*5=160
//4 1 2 3  (10,2)(2,3)(3,5)(5,10) 10*2*3+10*3*5+10*5*10=710
//逆时针 
//1 4 3 2  (2,3)(10,2)(5,10)(3,5)头尾接不上 
//4 3 2 1
//3 2 1 4
//2 1 4 3
//显然,逆时针不属于该题,讨论的范围。
//该题只需考虑顺时针的情况,松了口气。
//样例通过,提交10分,测试点1,3-10WA,不敢相信 
//算法,没问题,怎么可能,重新读题 
//发现(4⊕1)=10×2×3=60,理解有误, 
//dp[i][i+k]=max(dp[i][i+k],dp[i][j]+dp[j+1][i+k]+a[i]*a[j+1]*a[i+k+1]);//此处写成dp[i][i+k]=max(dp[i][i+k],dp[i][j]+dp[j+1][i+k]+a[i]*a[j+1]*a[i+k]); 
//修改,提交0分,全WA,怎么可能
//重读代码,发现,测试语句未删除
//删除测试语句,提交AC。2019-1-27 11:52
//真是一步错,步步错,焦头烂额。
//读好题目,理解好样例是关键。 

//突然有一个疑问,NOIP的复赛题,除了简单输入输出数据外,还配了一个复杂的输入输出数据吗?2019-1-27 11:57
#include
#include
int a[210],dp[210][210];
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    int n,i,j,k,ans=-1;
    memset(dp,0,sizeof(dp));
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]),a[n+i]=a[i];
    for(k=1;k         for(i=1;i<=2*n;i++)
            for(j=i;j                 if(i+k<2*n)//此处写成 if(i+k<=2*n)
                    dp[i][i+k]=max(dp[i][i+k],dp[i][j]+dp[j+1][i+k]+a[i]*a[j+1]*a[i+k+1]);//此处写成dp[i][i+k]=max(dp[i][i+k],dp[i][j]+dp[j+1][i+k]+a[i]*a[j+1]*a[i+k]); 
    for(i=1;i<=n;i++)ans=max(ans,dp[i][i+n-1]);
    printf("%d\n",ans);
    return 0;

5.找雷

//P2196 挖地雷
//NOIP 1996 提高组 第3题 共4题  
//2019-1-28 20:30翻看了之前编写的代码https://blog.csdn.net/mrcrack/article/details/78440134
//2019-1-29 06:00发现就是最长上升子序列的变形 
//感叹,当时能想出,现在怎么没想到呢。 
//有进有退,进多退少,总体是进步的。2019-1-29 08:02
//开始编码,有向图,用来判定两点是否联通 
//d[i]以i点为结尾的,挖的最多雷 
//打印路径过程,稍微有些小障碍,很快修改成功,
//样例通过,提交AC。2019-1-29 08:17 
#include
#include
int n,a[25],map[25][25],d[25],pre[25],last;//pre[i]=j i的上一个点来自j 
void print_path(int k){
    if(k==0)return;
    print_path(pre[k]);
    if(pre[k]==0)printf("%d",k);
    else printf(" %d",k);
}
int main(){
    int i,j,ans=0;
    memset(map,0,sizeof(map)),memset(pre,0,sizeof(0));
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
        for(j=i+1;j<=n;j++)
            scanf("%d",&map[i][j]);
    for(i=1;i<=n;i++){
        d[i]=a[i];
        for(j=1;j<=n;j++)
            if(map[j][i]&&d[j]+a[i]>d[i])
                d[i]=d[j]+a[i],pre[i]=j;
    }
    for(i=1;i<=n;i++)
        if(ans             ans=d[i],last=i;
    print_path(last);
    printf("\n%d\n",ans);
    return 0;
}

//P2196 挖地雷
//NOIP 1996 提高组 第3题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P2196
//N<=20,第1直觉,深搜dfs可行
//选择一条路径,又想到图
//题目写得很清楚,很好懂
//该题需打印路径,需费些心
//看了样例,发现是有向图
//准备采用类Floyd算法,有些累了,先休息。2019-1-27 21:18
//考虑之后,决定用 深搜dfs试试,看看能不能解决路径问题
//在打印路径编写过程中,发现,对递归理解更深刻了。
//出现最大值时,马上存储路径,虽然之后的路径会变。
//样例通过,提交AC。深搜dfs水平确实高了许多。2019-1-28 13:55
#include
#include
int a[25],map[25][25],n,vis[25],ans=0,b[25],path[25];
void dfs(int step,int start,int sum){
    int i,j;
    if(ans         ans=sum;
        path[0]=step;
        for(j=1;j<=step;j++)path[j]=b[j];
    }
    for(i=1;i<=n;i++)
        if(vis[i]==0&&map[start][i]==1){
            vis[i]=1;
            b[step+1]=i;
            dfs(step+1,i,sum+a[i]);
            vis[i]=0;
        }
}
int main(){
    int i,j;
    memset(map,0,sizeof(map));
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
        for(j=i+1;j<=n;j++)
            scanf("%d",&map[i][j]);
    for(i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        vis[i]=1;
        b[1]=i;
        dfs(1,i,a[i]);//此处写成 dfs(1,i,0);
        vis[i]=0;
    }
    printf("%d",path[1]);
    for(i=2;i<=path[0];i++)printf(" %d",path[i]);
    printf("\n%d\n",ans);
    return 0;
}

并查集

6.亲戚

//1073 家族
//在线测评地址http://codevs.cn/problem/1073/
//该题就是一个裸的并查集
//样例很快通过,提交AC. 2019-1-18
#include
#define maxn 5100
int n,m,p,f[maxn];
int getf(int u){
    if(f[u]==u)return u;
    return f[u]=getf(f[u]);
}
void merge(int u,int v){
    int f1=getf(u),f2=getf(v);
    if(f1!=f2)//左靠
        f[f2]=f1;
}
int main(){
    int i,x,y,f1,f2;
    scanf("%d%d%d",&n,&m,&p);
    for(i=1;i<=n;i++)f[i]=i;
    while(m--){
        scanf("%d%d",&x,&y);
        merge(x,y);
    }
    while(p--){
        scanf("%d%d",&x,&y);
        f1=getf(x),f2=getf(y);
        if(f1==f2)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

贪心

7.观光公交

heap

8.合并果子

//P1090 合并果子
//NOIP 2004 提高组 第2题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1090 
//用该题演练STL中的堆函数 
//样例通过,提交AC。2019-1-28 20:42 
//做个说明,弹出元素,从顶部,a[1];加入元素,从尾部,a[n] 
//默认是 大根堆。 
//若要小根堆,需加cmp函数, a>b 
//若加了cmp函数,则make,pop,push函数,均需加此cmp函数。否则,均无法实现功能。 
//STL的堆函数处理堆问题,代码量太小了。2019-1-28 20:45 
#include
#include
using namespace std;
int n,h[10100];
int cmp(int a,int b){
    return a>b;
}
int main(){
    int i,ans=0,m,a,b;
    scanf("%d",&n),m=n-1;
    for(i=1;i<=n;i++)scanf("%d",&h[i]);
    make_heap(h+1,h+1+n,cmp);
    for(i=1;i<=m;i++){
        a=h[1],pop_heap(h+1,h+1+n,cmp),n--;//此处写成 pop_heap(h+1,h+1+n)
        b=h[1],pop_heap(h+1,h+1+n,cmp);
        ans+=a+b;
        h[n]=a+b,push_heap(h+1,h+1+n,cmp);//此处写成 push_heap(h+1,h+1+n)
    }
    printf("%d\n",ans);
    return 0;
}

模拟

9.寻宝

//P1076 寻宝
//NOIP 2012 普及组 第2题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1076 
//题目很长,耐心多读几遍,很重要。 
//弄懂题意最好的办法,就是对样例进行模拟,模拟如下: 

2(1,2)   1(1,5)    0(0,1)   第2层   第1次出现在  2(1,2)      密码为(3+2)%20123=5 第N层无需再找有楼梯的房间

2(1,4)   1(0,3)    0(1,2)   第1层   第1次出现在  1(0,3)  能上楼的房间 找第3个有楼梯的房间 找到2(1,4)

//比如当前房间的指示牌上写着2,则按逆时针方向开始尝试,找到第2个有楼梯的房间
//上面这句很关键,请注意,不是连续找2个房间,是找2个有楼梯的房间。 
//该题需开一个结构体的二维数组,存储房间信息
//该题还需开一个二维数组,逆时针指向有楼梯的房间的序号。 
//看了数据范围,二维数组不会爆内存 
//采用模运算,不会超时 
//样例通过,提交0分,全WA。2019-1-23 20:40
//利用https://www.luogu.org/discuss/show/23296中的数据,进行跟踪 

5 4
1 5
1 8
0 5
1 6
0 7
1 65
1 4
0 56
1 8
1 7
1 9
0 11
1 15
1 78
1 98
1 87
1 54
0 45
1 56
1 44
2
153

//b[i][]数组存储无误 
//怎么查都查不出,又读了一遍题目,才发现“如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。” 
//题意理解有误啊,误以为,上到的这个房间有楼梯,就可以直接到达上一层,其实不是,还需要再找多个房间。 
//else{//看题,没抓住题意,导致该else功能的缺失。
//修改,提交0分,全WA。2019-1-23 21:35
//将 近1年前AC的代码,调出来,对比了测试数据的输出情况,才发现 
//now变量指的是在b[i][]中的位置,而不是在q[i][]中的位置。 
//修改,提交AC。2019-1-23 22:02 
//该题是道 纯模拟的题,难在 所有房间, 有楼梯的房间 之间的转换,如本人编写的now变量的意义。 
//难得,近1年前一次编写成功,而今,却反复编写,却WA。

//上述数据,执行过程如下:

i=1 start=0 ans=5
i=2 start=1 ans=12
i=3 start=1 ans=19
i=4 start=2 ans=97
i=5 start=3 ans=153
153
//以下为AC代码。 
#include
#define mod 20123 
struct node{
    int have,num;
}q[10010][105];
int b[10010][105],N,M,ans=0,start;
int main(){
    int i,j,now;
    scanf("%d%d",&N,&M);
    for(i=1;i<=N;i++){
        b[i][103]=0;//用来存储,有楼梯的房间数 
        for(j=0;j             scanf("%d %d",&q[i][j].have,&q[i][j].num);
            if(q[i][j].have)b[i][b[i][103]++]=j;
        }
    }
    scanf("%d",&start);
    for(i=1;i<=N;i++){
        ans=(ans+q[i][start].num)%mod;
        if(!q[i][start].have){
            //找到无楼梯房间之前的第1个有楼梯房间 
            if(start             else if(start>b[i][b[i][103]-1])now=b[i][103]-1;//此处写成now=b[i][b[i][103]-1];//无楼梯房间在所有有楼梯房间的最后面
            else{//无楼梯房间在所有有楼梯房间的中间
                for(j=0;j                     if(b[i][j]                         now=j;//此处写成now=b[i][j]; 
                        break;
                    }
            }
            now=(now+q[i][start].num)%b[i][103];//得到房间序号,在b[i][]中的位置
            start=b[i][now]; 
        }else{//看题,没抓住题意,导致该else功能的缺失。
            for(j=0;j                 if(start==b[i][j]){
                    now=j; 
                    break;
                }
            now=(now+q[i][start].num-1)%b[i][103];
            start=b[i][now];
        }
    }
    printf("%d\n",ans);
    return 0;
}

hash

10.方程的解数

//1735 方程的解数
//NOI 2001 共6题 
//在线测评地址http://codevs.cn/problem/1735/ 
//哈希表为什么要模以素数而非合数,此文讲得非常棒https://blog.csdn.net/zhishengqianjun/article/details/79087525
//哈希表解决此题的思路,该文讲得很好https://blog.csdn.net/fisher_jiang/article/details/667059
//哈希表早就习得,应用是第一次,甚是高兴,理论变现实。 
//因计算过程中的数据达到2^31,故采用桶排序,要爆内存,只能采用不爆内存的数组存储 
//其中就会遇到冲突,哈希表的算法就十分有用了, 
//关键有2个函数,一个是定位在数组中的位置,一个是将元素插入数组 
//一个比较大的质数4000037,先编程简单的验证,是否质数
//有个问题,要说明,哈希表中,绝对值相等的正负数,存储位置不一样 
//突然发现,英语很重要,是不是要把《新概念英语》背起来呢。 
//样例通过,提交AC。2019-2-2 12:07 
//该题收获,掌握了哈希表的写法。 
#include
#include
#define mod 4000037
#define LL long long
int n,m,k[10],p[10],mid;
int amount[mod],used[mod],ans[mod];
LL cnt=0;
int locate(int x){//只找不改。 
    int pos;
    pos=(mod+x%mod)%mod;//此处写成pos=(x+x%mod)%mod;,拔低了水平//x为负数,x为正数,均可处理,时间复杂度为O(1),处理出来的结果为非负数 
    while(used[pos]&&ans[pos]!=x){//冲突处理,该处已被占用,且不等于x 
        pos=(pos+1)%mod;
    }//跳出循环,要么该处没被占用;要么该处已被占用,存储的是数x 
    return pos;
}
void insert(int x){
    int pos;
    pos=locate(x);
    if(used[pos]&&ans[pos]==x)amount[pos]++;//该处已被占用,存储的是数x
    else used[pos]=1,ans[pos]=x,amount[pos]++;//该处没被占用; 代码虽然冗余,但是易懂,就不精简了 
}
LL quick_pow(int a,int b){
    LL ans=1;
    while(b){
        if(b&1)ans*=a;
        a*=a;
        b>>=1;
    }
    return ans;
}
void dfs_left(int step,int sum){//1->mid
    int i;
    if(step==mid+1){
        insert(sum);
        return ;
    }
    for(i=1;i<=m;i++)
        dfs_left(step+1,sum+k[step]*quick_pow(i,p[step]));
}
void dfs_right(int step,int sum){//mid+1->n 
    int i,pos;
    if(step+mid==n+1){//此处写成 if(step==n+1)
        pos=locate(-sum);// 右边结果等于左边结果的相反数 
        if(used[pos]&&ans[pos]==-sum)cnt+=amount[pos];
        return ;
    }
    for(i=1;i<=m;i++)
        dfs_right(step+1,sum+k[step+mid]*quick_pow(i,p[step+mid]));
}
int main(){
    int i;
    memset(ans,0,sizeof(ans)),memset(amount,0,sizeof(amount)),memset(used,0,sizeof(used));
    scanf("%d%d",&n,&m);
    mid=n/2;
    for(i=1;i<=n;i++)scanf("%d%d",&k[i],&p[i]);
    dfs_left(1,0);
    dfs_right(1,0);
    printf("%lld\n",cnt);
    return 0;

//验证4000037是质数的代码如下

#include
#define mod 4000037
int main(){
    int i;
    for(i=2;i*i<=mod;i++)
        if(mod%i==0)printf("No\n");
    printf("Yes\n");
    return 0;
}

//1735 方程的解数
//NOI 2001 共6题 
//在线测评地址http://codevs.cn/problem/1735/ 
//第一直觉 深搜dfs+剪枝,那点分数应该可以 
//指数的p次方,没说明范围,为了减少耗时,决定采用快速幂 
//为了尽可能的避免int溢出,决定采用long long
//用两个结构体,一个存非负系数,另一个存负系数 
//还好在int范围内测试了2^31=-2147483648,2^31-1=2147483647 
//核心,计算非负的绝对值,计算负的绝对值,比较是否相等,相等即为一种解。 
//样例通过,提交30分,测试点1,5-10TLE,目前尽力了。2019-2-1 16:13 
//以下为30分代码。 
#include
#include
#define LL long long
int n,m,cnt_b=0,cnt_c=0;
LL cnt=0;
struct node{
    LL k,p;
}b[10],c[10];
LL quick_pow(LL a,LL n){//快速幂 
    LL ans=1;
    while(n){
        if(n&1)ans*=a;//此处写成 if(n&2)ans*=a;
        a*=a;
        n/=2;
    }
    return ans;
}
void dfs_c(int step,LL sum1,LL sum2){
    int i;
    if(sum2>=((1<<31)-1))return;
    if(sum2>sum1)return;
    if(step==cnt_c+1&&sum1==sum2){
        cnt++;
        return ;
    }
    if(step==cnt_c+1)return;//漏了此功能,跟踪程序后才发现。此句很重要,足足耽搁了30分钟 
    for(i=1;i<=m;i++)
        dfs_c(step+1,sum1,sum2+c[step].k*quick_pow(i,c[step].p));
}
void dfs_b(int step,LL sum){
    int i;
    if(sum>=((1<<31)-1))return;
    if(step==cnt_b+1){
        dfs_c(1,sum,0);
        return;
    }
    for(i=1;i<=m;i++)
        dfs_b(step+1,sum+b[step].k*quick_pow(i,b[step].p));
}
int main(){
    int i;
    LL k,p;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%lld%lld",&k,&p);
        if(k>=0)cnt_b++,b[cnt_b].k=k,b[cnt_b].p=p;
        else cnt_c++,c[cnt_c].k=-k,c[cnt_c].p=p;//此处写成else cnt_c++,b[cnt_c].k=k,b[cnt_c].p=p;跟踪了程序才查出 
    }
    dfs_b(1,0);
    printf("%lld\n",cnt);
    return 0;

数论

11.数列

//P1062 数列
//NOIP 2006 普及组 第4题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1062 
//第1直觉,堆+深搜dfs,但是感觉不顺手,寻求它法 
//转换成进制,只需系数<=1即可,否则不符合要求,一个想法掠过 
//办法是好办法,就是担心超时,不过,很好编写,50分绝对有信心 
//程序很快编好,样例通过,开始测试极端情况
//3 1000 29430        很快 
//4 1000 349248       很快
//5 1000没有输出,果断将最大值开到10^7 结果为2440750 很快 
//6 1000没有输出,果断将最大值开到10^8 结果为12091896 很快
//7 1000                              结果为47076750 有些卡顿,但1s能过 
//8 1000没有输出,果断将最大值开到10^9 没有输出 有些卡顿,到头了, 
//程序需要修改,int需改成long long 
//8 1000 将最大值开到10^10 结果为 153387520 明显卡顿,1s过不了 
//该算法的极限到了,提交40分,测试点5-10TLE。2019-1-30 18:59
//以下为40分代码。
//突然想到,该题在考察二进制
//第1个数 1 
//第2个数 10
//第3个数 11
//第4个数 100
//第5个数 101
//第6个数 110
//第7个数 111
//该题迎刃而解,N转换成2进制的
//N=1000,对应2进制 1111101000 
//迅速将stack[100],改成stack[20] 
//编好后,马上测试8 1000又快又准, 
//测试15 1000,秒出41189262750 
//提交AC。2019-1-30 20:55
//完全独立想出,没有任何提示
//看来,看了两集《单挑荒野》还是有收获的,看好后,突然就想到了上述解法。 
#include
#define LL long long
int k,N,stack[20],top=0;
LL ans=0;
void to2(int x){//N转2进制 
    while(x){
        stack[++top]=x%2;
        x/=2;
    }
}
int main(){
    int i;
    scanf("%d%d",&k,&N);
    to2(N);
    for(i=top;i>=1;i--){//k进制转10进制 
        ans*=k;
        ans+=stack[i];
    }
    printf("%lld\n",ans);
    return 0;
}

//P1062 数列
//NOIP 2006 普及组 第4题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1062 
//第1直觉,堆+深搜dfs,但是感觉不顺手,寻求它法 
//转换成进制,只需系数<=1即可,否则不符合要求,一个想法掠过 
//办法是好办法,就是担心超时,不过,很好编写,50分绝对有信心 
//程序很快编好,样例通过,开始测试极端情况
//3 1000 29430        很快 
//4 1000 349248       很快
//5 1000没有输出,果断将最大值开到10^7 结果为2440750 很快 
//6 1000没有输出,果断将最大值开到10^8 结果为12091896 很快
//7 1000                              结果为47076750 有些卡顿,但1s能过 
//8 1000没有输出,果断将最大值开到10^9 没有输出 有些卡顿,到头了, 
//程序需要修改,int需改成long long 
//8 1000 将最大值开到10^10 结果为 153387520 明显卡顿,1s过不了 
//该算法的极限到了,提交40分,测试点5-10TLE。2019-1-30 18:59
//以下为40分代码。 
#include
#define LL long long
int k,N,cnt=0;
int judge(LL x){//0不符,1符合要求
    while(x){
        if(x%k>1)return 0;//系数 大于 1 
        x/=k;
    } 
    return 1;
}
int main(){
    LL i;
    scanf("%d%d",&k,&N);
    for(i=1;i<=10000000000LL;i++){// 10000000000LL此句写得不错 
        if(judge(i))cnt++;
        if(cnt==N){
            printf("%lld\n",i);
            break;
        }
    }
    return 0;
}

12.同余方程

//P1082 同余方程
//NOIP 2012 提高组 day2 第1题 day2 共3题 
//在线测评地址https://www.luogu.org/problemnew/show/P1082 
//ax+by=1,gcd(a,b)=1,肯定成立,因,输入数据保证一定有解 
//扩展欧几里得算法exgcd 
//因数据a,b最大值2000000000,采用long long比较稳妥 
//解决该题的过程,就是  扩展欧几里得算法 重新推导的过程 
//独立推导完成,没有借助任何资料。
//样例通过,提交AC。2019-1-30 16:53 
#include
int exgcd(int a,int b,int *x,int *y){
    int d,t;
    if(b==0){
        *x=1,*y=0;
        return a;
    }
    d=exgcd(b,a%b,x,y);
    t=*x,*x=*y,*y=t-a/b**y;
    return d;
}
int main(){
    int a,b,x,y;
    scanf("%d%d",&a,&b);
    exgcd(a,b,&x,&y);
    x=(b+x%b)%b;
    printf("%d\n",x);
    return 0;
}

13.多项式系数

//P1313 计算系数
//NOIP 2011 提高组 第2天 第1题  第2天 共3题 
//在线测评地址https://www.luogu.org/problemnew/show/P1313
//翻看本人之前代码,竟有逆元之说,决定停下脚步,把这些遗忘的知识拾起。
//通过此文https://www.cnblogs.com/rir1715/p/7748054.html瞬间搞懂了,逆元的计算公式。 
//逆元有一个要素,模运算的数字需是质数。其中用到了费马小定理 
//第1步,先验证10007是质数 
//发现是质数,可以开始乘法逆元
//有乘法逆元的地方,就有快速幂 
//样例通过,提交AC。2019-1-30 9:57 
//乘法逆元有些感觉了。 
#include
#define mod 10007
#define LL long long
LL quick_pow(int x,int n){
    LL ans=1;
    while(n){
        if(n&1)ans=(ans*x)%mod;
        x=(x*x)%mod;
        n/=2;
    }
    return ans;
}
int main(){
    int i,a,b,k,n,m;
    LL c=1,A=1,B=1,d=1,ans;
    scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
    for(i=k;i>=k-n+1;i--)c=(c*i)%mod;
    for(i=n;i>=1;i--)d=(d*i)%mod;
    c=(c*quick_pow(d,mod-2))%mod;//乘法逆元 
    for(i=1;i<=n;i++)A=(A*a)%mod;
    for(i=1;i<=m;i++)B=(B*b)%mod;
    ans=(c*A*B)%mod;
    printf("%lld\n",ans);

//P1313 计算系数
//NOIP 2011 提高组 第2天 第1题  第2天 共3题 
//在线测评地址https://www.luogu.org/problemnew/show/P1313 
//通项公式C(k,n)(ax)^n(by)^(k-n) 
//杨辉三角即可解决 C(k,n)
//因对10007取模,int不会溢出 
//测算了10007*1000000=10^10,int溢出,还需long long 
//for(i=0;i<=k;i++)c[i][i]=c[i][0]=1;//此处写成 for(i=0;i<=k;k++)c[i][i]=c[i][0]=1;查了20分钟
//测试的时候,就觉得奇怪,怎么会超1s,原来是笔误引出的。
//样例通过,提交50分,测试点2,3,6-8 WA.2019-1-30 8:38
//怎么可能,重新读题,对特殊情况,进行理解,没问题啊 
//再读代码,又发现一处笔误
//for(i=1;i<=m;i++)B=(B*b)%mod;//此处写成 for(i=1;i<=m;i++)B=(B*a)%mod; 导致提交50分
//修改,提交AC,2019-1-30 8:44
//提交前,还是要多测试,笔误之类的,完全能在测试中发现,这样,提交,更有信心。 
#include
#define LL long long
#define mod 10007
int a,b,k,n,m,c[1010][1010];
LL A=1,B=1,ans;
int main(){
    int i,j;
    scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
    for(i=0;i<=k;i++)c[i][i]=c[i][0]=1;//此处写成 for(i=0;i<=k;k++)c[i][i]=c[i][0]=1;查了20分钟 
    for(i=2;i<=k;i++)//此处写成 for(i=1;i<=k;i++)
        for(j=1;j             c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    for(i=1;i<=n;i++)A=(A*a)%mod;
    for(i=1;i<=m;i++)B=(B*b)%mod;//此处写成 for(i=1;i<=m;i++)B=(B*a)%mod; 导致提交50分 
    ans=(c[k][n]*A*B)%mod;
    printf("%lld\n",ans);
    return 0;
}

dfs

14.选数

//P1036 选数
//NOIP 2002 普及组  第2题  共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1036 
//深搜dfs即可解决。 
//最大和,5000000*20=10^8,int不会溢出 
//样例通过,提交AC。2019-1-22 19:47 
//翻看代码,比2年前,写得棒多了。 
#include
#define maxn 25
int a[maxn],n,k,cnt=0;
int isPrime(int x){//素数返回1,非素数返回0 
    int i;
    if(x==1)return 0;
    if(x==2)return 1;
    for(i=2;i*i<=x;i++)
        if(x%i==0)return 0;
    return 1;
}
void dfs(int step,int start,int sum){
    int i;
    if(step==k+1){
        if(isPrime(sum))cnt++;
        return ;
    }
    for(i=start;i<=n;i++)
        dfs(step+1,i+1,sum+a[i]);//此处写成i+1甚为精妙 
}
int main(){
    int i;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(1,1,0);
    printf("%d\n",cnt);
    return 0;
}

高精度

15.回文数

//P1015 回文数
//NOIP 1999 提高组  第2题  共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1015
//测算int或是long long 是否会溢出
//98+89=187  187+781=968  968+869=1837  1837+7381=9218
//9218+8129=17347  17347+74371=91718  91718+81719=173437
//173437+734371=907808 907808+808709=1716517
//1716517+7156171=872688
//受不了了,还是编个程序测试了再说
//测试98,int没有溢出,测试99,int溢出
//想过用long long,但该题已经没有意义,因为是设计N进制
//改成字符串,省时省力,用高精度加
//该题,还需特判,如,输入的数,本身就是回文
//读题,发现进制数M(100位之内),看成了100之内,还好及时发现
//因涉及16进制,故不采用int
//再想想,加法计算不好处理,决定还是从char a[]回归到int a[]
//样例通过,提交25分,测试点1,2,4 WA
//这么简单的题,怎么会错,仔细想了想,做该题过程中,被打断了四次
//错也难怪,错了之后,马上想到,是M进制,编的过程中,写成了10进制
//马上修改,提交75分,测试点2 WA。
//翻看了https://www.luogu.org/discuss/show/53147讨论,输入数据也可以是16进制,昏倒
//缺失没考虑到
//修改,提交AC。2019-1-24
#include
#include
#define maxn 1000000
int N;
int a[maxn],b[maxn],c[maxn];
char s[maxn];
int judge(int *s){
    int i;
    for(i=1;i<=s[0]/2;i++)
        if(s[i]!=s[s[0]-i+1])
            return 0;//非回文
    return 1;//回文
}
void reverse(int *x,int *y){
    int i;
    y[0]=x[0];
    for(i=1;i<=x[0];i++)y[x[0]-i+1]=x[i];
}
void add(int *x,int *y){
    int i;
    memset(c,0,sizeof(c));
    c[0]=x[0];
    for(i=1;i<=c[0];i++){
        c[i]+=x[i]+y[i];
        c[i+1]+=c[i]/N;//此处写成 c[i+1]+=c[i]/10;
        c[i]%=N;//此处写成c[i]%=10;
    }
    if(c[i])c[0]=i;
    memcpy(a,c,sizeof(c));
}
int main(){
    int i;
    scanf("%d%s",&N,s+1);
    a[0]=strlen(s+1);
    for(i=1;i<=a[0];i++)
        if('A'<=s[i]&&s[i]<='F')a[i]=s[i]-'A'+10;
        else if('a'<=s[i]&&s[i]<='f')a[i]=s[i]-'a'+10;
        else a[i]=s[i]-'0';//只考虑了0-9
    if(judge(a))printf("STEP=0\n");//特判
    else{
        for(i=1;i<=30;i++){
            reverse(a,b);
            add(a,b);
            if(judge(a)){
                printf("STEP=%d\n",i);
                break;
            }
        }
        if(i==30+1)printf("Impossible!\n");
    }
    return 0;
}

模拟

16.现在几点钟

//1063: 现在几点钟?
//在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1063 
//问题中,表述的东西比较多 
//按先特判,再一般情形,程序会比较容易编写。 
//测试了几组时间数据的读取 
//1:00 读入1 0
//1:03 读入1 3
//开始进行特判的处理
//突然发现,英语没学好的,这个题目难以做好,有一堆单词要独立写出 
//编写一个时间,测试一个时间
//问题中给的数据全部通过,提交AC。眼泪都要掉下来了,生怕英文单词写错
//基本可判定,问题中给出的数据,就是该问题的测试点。2019-1-22 21:05
//该题,主要在练,if else + 字符串简单处理。 
#include
#include
int h,m;
char num[][20]={"","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","thirty","forty"};
char ten[][20]={"","","twenty","thirty","forty"};
int main(){
    char s[20];
    scanf("%d:%d",&h,&m);
    if(m==0){//5:00 Five o'clock
        strcpy(s,num[h]);
        s[0]=s[0]-'a'+'A';
        printf("%s o'clock\n",s);
    }else if(m==15){//5:15 Quarter past five
        printf("Quarter past %s\n",num[h]);
    }else if(m==45){//5:45 Quarter to six 
        if(h==12)h=1;//要小心12 与  1的关系 
        else h+=1;
        printf("Quarter to %s\n",num[h]);
    }else if(m<45){
        strcpy(s,num[h]);
        s[0]=s[0]-'a'+'A';
        printf("%s ",s);
        if(m<=20)printf("%s",num[m]);//10:10 Ten ten
        else{//9:22 Nine twenty-two 2:30 Two thirty  6:40 Six forty
            printf("%s",ten[m/10]);
            if(m%10)printf("-%s",num[m%10]);
        }
    }else if(m>45){//8:47 Thirteen to nine  12:47 Thirteen to one (American time: 1:00 follows 12:00)
        strcpy(s,num[60-m]);
        s[0]=s[0]-'a'+'A';
        printf("%s",s);
        if(h==12)h=1;//要小心12 与  1的关系 
        else h+=1;
        printf(" to %s",num[h]);
    }
    return 0;
}
 

17.选择客栈

//P1311 选择客栈
//NOIP 2011 提高组 day1 第2题 day1 共3题 
//在线测评地址https://www.luogu.org/problemnew/show/P1311
//有O(n)的算法,那么要好好学习
//https://www.luogu.org/problemnew/solution/P1311的作者: ShawnZhou可以看看 
//以下是改进,更易于理解。 
//思路,有些类似 归并排序求逆序对,最长上升子序列。都是以i为结尾的情况分析。 
//样例通过,提交AC。2019-1-31 22:54 
#include
#include
#define LL long long
#define maxn 55
int cnt[maxn],last[maxn],sum[maxn];//cnt[j]j颜色的数量 last[j] j颜色历此次最近一次出现的位置 sum[j] j颜色在now位置之前(包含)出现的次数 
int main(){
    int i,now=0,color,price,n,k,p;
    LL ans=0;
    scanf("%d%d%d",&n,&k,&p);
    memset(cnt,0,sizeof(cnt)),memset(last,0,sizeof(last));
    for(i=1;i<=n;i++){
        scanf("%d%d",&color,&price);
        if(price<=p)now=i;//更新最新喝咖啡客栈位置
        if(now>=last[color])sum[color]=cnt[color];//在now之前(包含)color客栈的数量
        ans+=sum[color];//以客栈i为结尾的符合条件的客栈的个数,有点象 归并排序求逆序对 
        last[color]=i;//更新color客栈最新位置
        cnt[color]++; 
    }
    printf("%lld\n",ans); 
    return 0;
}

//P1311 选择客栈
//NOIP 2011 提高组 day1 第2题 day1 共3题 
//在线测评地址https://www.luogu.org/problemnew/show/P1311 
//因n=200000,算法的时间复杂度,要么O(n),要么O(nlogn). 
//该题,要得50分,即n=1000,采用O(n^2)的算法,还是比较简单的 
//sum[i][j]以i客栈为结尾j颜色客栈的数量 
//该题纯模拟+数组的组合知识 即可。
//int可能溢出,考虑用long long
//样例通过,提交AC。2019-1-31 18:23
//纯模拟,算法的时间复杂度O(nk)
//自我感觉,这个算法程序易编出,也不容易出错。 
#include
#include
#define LL long long
int n,k,p,q[200010],color[55],b[200010];//b[i] i位置的颜色 
LL sum[200010][55],ans=0;
int main(){
    int i,j,c,consume,now;
    memset(sum,0,sizeof(sum)),memset(color,0,sizeof(color));
    scanf("%d%d%d",&n,&k,&p);
    for(i=1;i<=n;i++){//时间复杂度nk,应该能险过 
        scanf("%d%d",&c,&consume);//此处写成 scanf("%d%d",&c,consume); 查了会 
        color[c]++,b[i]=c;
        for(j=0;j         q[i]=consume;
    }
    now=0;
    for(i=1;i<=n;i++)
        if(q[i]<=p){
            for(j=0;j                 if(b[i]==j)//最低消费客栈,参与住宿1 2 3(最低消费,参与住宿) 4 5  2*3+2=8 
                    ans+=(sum[i-1][j]-sum[now][j])*(sum[n][j]-sum[i-1][j])+sum[n][j]-sum[i][j];
                else//最低消费客栈,不参与住宿 1 2 3(最低消费,不参与住宿) 4 5  2*2=4
                    ans+=(sum[i-1][j]-sum[now][j])*(sum[n][j]-sum[i-1][j]);
            now=i;
        }
    printf("%lld\n",ans);
    return 0;
}

18.机器翻译

//P1540 机器翻译
//NOIP 2010 提高组 第1题  共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1540
//队列
//样例通过,提交AC。2019-1-23 17:25
//感觉,比起从前,该题变得太轻松了。
#include
#include
#define maxn 1100
int q[maxn],h,t;
int main(){
    int m,n,a,i,cnt=0;
    memset(q,0,sizeof(q));
    scanf("%d%d",&m,&n);
    h=t=1;
    while(n--){
        scanf("%d",&a);
        for(i=h;i             if(q[i]==a)break;
        if(i==t){//i==t发生在,没找到该单词
            cnt++;
            if(t-h                 q[t]=a,t++;
            else//清理内存,加入内存
                h++,q[t]=a,t++;
        }
    }
    printf("%d\n",cnt);
    return 0;
}

19.计算器的改良

//P1022 计算器的改良
//NOIP 2000 普及组 第1题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1022 
//该题有现实意义,有些计算器提供了解方程的功能 
//读完题,没什么好思路,纯模拟 
//字符串读入,之后进行解析,处理 
//测试了,3+-3发现能正确运算,3--3报错,-3+-3能正确运算,-3--3报错 
//考什么呢,不过需求来源于生活,首要就是将其解决,再考虑优化
//对样例进行研究 
//6a-5+1=2-2a  a=0.750
//6a-5+1=-2a+2 a=0.750
//提交AC。2019-1-31 12:18
//从左往右扫的过程中,找出数字是关键,数字之前是符号,数字之后是未知数或等号或符号,等号之前是未知数或数字 
//该题纯模拟,没有什么技巧,不过需注意一些特殊情况。 
#include
#include
char s[1000];
int main(){
    int i,len,op,d,fm=0,fz=0,right=0;//op为1表示负数,op为0表示正数 fm分母,fz分子 
    char alpha;
    scanf("%s",s);
    len=strlen(s);
    i=0;
    while(i         d=0,op=0;
        while('0'<=s[i]&&s[i]<='9'){
            if(i-1<0)op=0;
            else if(s[i-1]=='+')op=0;
            else if(s[i-1]=='=')op=0,right=1;
            else if(s[i-1]=='-')op=1;
            d*=10,d+=s[i]-'0',i++;
        }//数字处理
        if('a'<=s[i]&&s[i]<='z'){//未知数及系数处理 
            alpha=s[i];
            if(right==0){
                if(d==0)fm+=1;
                else if(op==0)fm+=d;
                else if(op==1)fm-=d;
            }else{
                if(d==0)fm-=1;
                else if(op==0)fm-=d;
                else if(op==1)fm+=d;
            }
            
        }else if(right==0){
            if(op==0)fz-=d;
            else if(op==1)fz+=d;
        }else if(right==1){
            if(op==0)fz+=d;
            else if(op==1)fz-=d;
        } 
        if(s[i]=='=')right=1;//漏了此句,通过测试数据6a-5+1=-2a+2 a=0.750,发现了疏漏 
        i++; 
    }
    printf("%c=%.3lf\n",alpha,fz*1.0/fm);
    return 0;
}

20.分数线划定

//P1068 分数线划定
//NOIP 2009 普及组 第2题  共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1068
//排序采用sort函数
//样例通过,提交,再次遇到Compile Error,爆0   
//可怜的windows下的C++编成,头文件,缺失,编译器竟然不提示
//添加头文件,提交AC。2019-1-23
//感觉编得比以前轻松,但是C++隐患太大,需到linux环境中,C++编写,才有保障
#include
#include
#include //漏了此头文件
using namespace std;
#define maxn 5100
struct node{
    int seq,score;
}q[maxn];
int cmp(const struct node &a,const struct node &b){//自大到小
    if(a.score==b.score)return a.seq     return a.score>b.score;//此处写成return a.score }
int main(){
    int n,m,i,p,cnt,score;
    memset(q,0,sizeof(q));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d%d",&q[i].seq,&q[i].score);
    sort(q+1,q+1+n,cmp);
    cnt=p=(int)(m*1.5);
    score=q[cnt].score;
    while(q[cnt+1].score==score)cnt++;//从p位置开始数
    printf("%d %d\n",score,cnt);
    for(i=1;i<=cnt;i++)printf("%d %d\n",q[i].seq,q[i].score);
    return 0;
}

进制

21.进制转换

//P1017 进制转换
//NOIP 2000 第1题 共4题 
//在线测评地址https://www.luogu.org/problemnew/show/P1017 
//做惯了 正数 正基数,突然遇到了 负基数 正数或负数 
//卡顿了很长时间, 
//反复对比 正数 正基数,以及 余数 需小于 负基数的绝对值 ,才基本明白该题中的进制转换 
//-15,-2;15,-2模拟如下 

重走长征路---OI每周刷题记录---11月4日 2013_第1张图片

 

 

//该题难在,思考出上述模拟过程 
//需简单测试,负数的除模运算。
//-15/-2=7,-15%-2=-1;15/-2=7,15%-2=1
//负数没法用除模运算,得自己编;正数还能用用 
//-15/-2这样处理15/2=7,商7+1=8,余数-15-(-2*8)=1 
//因输入是10进制,输入处理就比较轻松。 
//N=0需特判 
//在犹豫,16进制打印大写字母,还是小写字母,发现样例4已经给出了结果 
//样例通过,提交AC.2019-1-29 20:06
//为了弄清,栈空间,做了如下测试。 
//-32768 -2
//-32768=1000000000000000(base-2) 
//32767 -2
//32767=11000000000000011(base-2)
//空间开100足以 
//修改,提交AC。2019-1-29 20:10 
#include
int N,R,m,s;//m对应负数N的绝对值,s对应负数R的绝对值 
int stack[100],top=0;//开多少位比较合适呢?不要小气,大气些,先开10000,具体可编好后测试,测试发现100足以 
int main(){
    int i;
    scanf("%d%d",&N,&R);
    printf("%d=",N);
    if(N==0){//N=0需特判
        printf("0(base%d)\n",R); 
        return 0;
    }
    while(N){
        if(N<0){
            m=-N,s=-R;
            if(m%s==0){//能整除 
                N=m/s;
                stack[++top]=0;
            }else{//不能整除
                stack[++top]=N-(m/s+1)*R;
                N=m/s+1; 
            }
        }else{//N>0
            stack[++top]=N%R;
            N/=R;
        }
    }
    for(i=top;i>=1;i--){
        if(stack[i]<10)printf("%d",stack[i]);
        else printf("%c",stack[i]-10+'A');
    }
    printf("(base%d)\n",R);
    return 0;

枚举

22.一元三次方程求解

//P1024 一元三次方程求解
//NOIP 2001 提高组  第1题  共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1024
//因根的范围在-100-100之间,精确到小数点后2位 ,只需计算-100.00-100.00
//为了更精确,计算-100.0000-100.000即可,需算2000000,稳过,综上所述,该题傻算即可。
//样例没通过,重新看了题目,发现4个实数A,B,C,D,之前误以为是4个整数,还好样例没通过,马上修改
//发现 return fabs(a*x*x*x+b*x*x+c*x+d);//此处写成 return a*x*x*x+b*x*x+c*x+d;
//应是比较的绝对值
//提交AC。2019-1-24
//对比了该题之前编写的代码,发现应试能力有了大大的提高。
#include
#include
#define eps 1e-7
double f(double a,double b,double c,double d,double x){
    return fabs(a*x*x*x+b*x*x+c*x+d);//此处写成 return a*x*x*x+b*x*x+c*x+d;
}
int main(){
    int i,cnt=0;
    double a,b,c,d,x;
    scanf("%lf%lf%lf%lf\n",&a,&b,&c,&d);
    for(i=0;i<=2000000;i++){
        x=-100+0.0001*i;
        if(f(a,b,c,d,x)<=eps){
            printf("%.2lf ",x);
            cnt++;
            if(cnt==3)break;
        }
    }
    return 0;
}

 

你可能感兴趣的:(跟着大佬学算法)