总目录详见https://blog.csdn.net/mrcrack/article/details/84471041
做题原则,找不到测评地址的题不做。2018-11-28
重走长征路---OI每周刷题记录---10月12日 2013
本周共计7题
测评地址:
模拟
1.美元 //在线测评地址http://codevs.cn/problem/2209/
dp
2.乘积最大 //在线测评地址https://www.luogu.org/problemnew/show/P1018
http://codevs.cn/problem/1017/
3.传球游戏 //在线测评地址https://www.luogu.org/problemnew/show/P1057
4.摆花 //在线测评地址https://www.luogu.org/problemnew/show/P1077
背包dp
5.公路乘车 //在线测评地址http://codevs.cn/problem/2154/
6.找啊找啊找gf //在线测评地址https://www.luogu.org/problemnew/show/P1509
dfs
7.n皇后 //在线测评地址http://codevs.cn/problem/2194/
题解:
模拟
1.美元
//2209 美元=doller=刀=knife
//在线测评地址http://codevs.cn/problem/2209/
//题意没说明,应该是该天,可买也可不买,回头看看,只是通过样例做了说明
//该题核心是,找到买点(峰),根据买点找卖点(谷)
//对最后一个买点进行特判,看是买还是不买
//该题思维量挺大
//极端数据1000买进,1卖出,共计50次操作100*10^50=10^52 int肯定溢出,long long 也溢出
//不过,不准备采用高精度算法,采用long long 多拿些分数
//看了输出结果,多虑了,采用double即可。
//样例通过,提交,测试点4,5,7,8,9,10WA,得分40
//以下为40分代码。2018-12-30 19:27
//基本确认,是上述算法的问题,没有数据,很难找到算法问题
//找到新的在线测评地址https://www.luogu.org/problemnew/show/P1968
//提交,发现测试点4,5,7-10WA。
//发现之前做过,但与今日思路完全不同,看看题解里是否有数据,或与今日思路相近算法
//翻看此文代码https://blog.csdn.net/wx2306/article/details/79213196恍然大悟
//是自己想得太简单,还是想得太复杂了?
//该题的算法比较符合人性,有得赚就走。无论你是怎么想的,这就是最赚钱的办法
//是故不积跬步,无以致千里;不积小流,无以成江海。
//样例通过,提交AC。2018-12-30 20:18
//以下为AC代码。
#include <stdio.h>
int a[110];
double ans=100;
int main(){
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<n;i++)
if(a[i]>a[i+1])
ans=ans*a[i]/a[i+1];
printf("%.2lf\n",ans);
return 0;
}
//2209 美元=doller=刀=knife
//在线测评地址http://codevs.cn/problem/2209/
//题意没说明,应该是该天,可买也可不买,回头看看,只是通过样例做了说明
//该题核心是,找到买点(峰),根据买点找卖点(谷)
//对最后一个买点进行特判,看是买还是不买
//该题思维量挺大
//极端数据1000买进,1卖出,共计50次操作100*10^50=10^52 int肯定溢出,long long 也溢出
//不过,不准备采用高精度算法,采用long long 多拿些分数
//看了输出结果,多虑了,采用double即可。
//样例通过,提交,测试点4,5,7,8,9,10WA,得分40
//以下为40分代码。2018-12-30 19:27
//基本确认,是上述算法的问题,没有数据,很难找到算法问题
//找到新的在线测评地址https://www.luogu.org/problemnew/show/P1968
//提交,发现测试点4,5,7-10WA。
//发现之前做过,但与今日思路完全不同,看看题解里是否有数据,或与今日思路相近算法
//翻看此文代码https://blog.csdn.net/wx2306/article/details/79213196恍然大悟
//是自己想得太简单,还是想得太复杂了?
//该题的算法比较符合人性,有得赚就走。无论你是怎么想的,这就是最赚钱的办法
//是故不积跬步,无以致千里;不积小流,无以成江海。
//样例通过,提交AC。2018-12-30 20:18
//以下为AC代码。
//翻看了之前的代码,发现写得挺妙,但决不是自己想出来的。动态规划
//思路如下,同一天兑换成美元或马克,都对应最大值
//样例通过,提交AC。2018-12-30 21:08
#include <stdio.h>
double dp1=100,dp2=0;//dp1 最大美元值,dp2 最大马克值 均发生在当日
double max(double a,double b){
return a>b?a:b;
}
int main(){
int n,i,a;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a);
dp1=max(dp1,dp2*100/a);
dp2=max(dp2,dp1*a/100);
}
printf("%.2lf\n",dp1);
return 0;
}
//2209 美元=doller=刀=knife
//在线测评地址http://codevs.cn/problem/2209/
//题意没说明,应该是该天,可买也可不买,回头看看,只是通过样例做了说明
//该题核心是,找到买点(峰),根据买点找卖点(谷)
//对最后一个买点进行特判,看是买还是不买
//该题思维量挺大
//极端数据1000买进,1卖出,共计50次操作100*10^50=10^52 int肯定溢出,long long 也溢出
//不过,不准备采用高精度算法,采用long long 多拿些分数
//看了输出结果,多虑了,采用double即可。
//样例通过,提交,测试点4,5,7,8,9,10WA,得分40
//以下为40分代码。2018-12-30 19:27
#include <stdio.h>
int a[110],b[110];//b[i]买点
double ans=100;
int main(){
int n,i,j;
scanf("%d",&n);
a[0]=a[n+1]=0;//为了找出峰值而设计
for(i=1;i<=n;i++)scanf("%d",&a[i]);
b[0]=0;
for(i=1;i<=n;i++)
if(a[i-1]<a[i]&&a[i]>=a[i+1])
b[++b[0]]=i;//存储峰值位置
for(i=1;i<b[0];i++)
for(j=b[i]+1;j<=b[i+1]-1;j++)//找谷,卖点
if(a[j-1]>=a[j]&&a[j]<a[j+1]){
ans=ans*a[i]/a[j];
break;
}
//最后一个买点进行特判,买还是不买
a[n+1]=1100;//为了找出最后的 谷 而设计,因1≤A≤1000
for(j=b[0]+1;j<=n;j++)
if(a[j-1]>=a[j]&&a[j]<a[j+1]){
ans=ans*a[b[b[0]]]/a[j];//此处写成 ans=ans*a[b[0]]/a[j];
break;
}
printf("%.2lf\n",ans);
return 0;
}
dp
2.乘积最大
//P1018 乘积最大
//NOIP 2000 提高组
//在线测评地址https://www.luogu.org/problemnew/show/P1018
//没什么太好的办法,决定采用深搜dfs
//算法的时间复杂度40^6=4*10^9拿部份分吧
//考虑了一下,结果采用long long
//样例通过,提交,测试点7-10WA,60分,深搜差不多到头了。
//以下为60分代码。2018-12-31 13:44
//不用高精度,若想AC,可在此处提交http://codevs.cn/problem/1017/
#include <stdio.h>
#include <string.h>
#define LL long long
int N,K;
char s[50];
int a[50],b[50];
LL ans=-1;
LL max(LL a,LL b){
return a>b?a:b;
}
LL value(int start,int end){
int i;
LL c=0;
for(i=start;i<=end;i++){
c*=10;
c+=a[i];
}
return c;
}
void dfs(int step){
int i,j;
LL d=1;
if(step==K+1){
for(j=1;j<=K;j++)
d*=value(b[j-1]+1,b[j]);//此处写成 d*=value(b[j-1],b[j]);
d*=value(b[K]+1,N);//最后一个数字特判
ans=max(ans,d);
return;
}
for(i=b[step-1]+1;i<=N;i++){
b[step]=i;
dfs(step+1);
}
}
int main(){
int i;
scanf("%d%d%s",&N,&K,s+1);
for(i=1;i<=N;i++)a[i]=s[i]-'0';
b[0]=0;
dfs(1);
printf("%lld\n",ans);
return 0;
}
3.传球游戏
//P1057 传球游戏
//NOIP 2008 普及组
//在线测评地址https://www.luogu.org/problemnew/show/P1057
//递推公式容易想到f[i][j]=f[i-1][j-1]+f[i-1][j+1]
//难点在于 如何赋初值 边界处理 循环是先n还是m
//以上难点由 模拟 样例 来解决
//在考虑f[][]采用int还是long long
//还是测试一下,比较稳妥,
//测试了 30 30
//输出155117522
//放心了,提交AC。2019-1-1 08:13
#include <stdio.h>
#include <string.h>
int f[35][35];
int main(){
int n,m,i,j,a,b;
memset(f,0,sizeof(f)),f[0][1]=1;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
a=j-1,b=j+1;
if(a==0)a=n;
if(b==n+1)b=1;
f[i][j]=f[i-1][a]+f[i-1][b];
}
printf("%d\n",f[m][1]);
return 0;
}
4.摆花
//P1077 摆花
//NOIP 2012 普及组
//在线测评地址https://www.luogu.org/problemnew/show/P1077
//方案数
//样例通过,提交AC。2018-12-31 22:19
#include <stdio.h>
#include <string.h>
#define mod 1000007
int f[110][110],a[110];
int main(){
int n,m,i,j,k;
memset(f,0,sizeof(f));
f[0][0]=1;//此句很关键
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)
for(k=0;k<=a[i];k++)
if(j>=k)f[i][j]=(f[i][j]+f[i-1][j-k])%mod;
printf("%d\n",f[n][m]);
return 0;
}
背包dp
5.公路乘车
//2154 公路乘车
//在线测评地址http://codevs.cn/problem/2154/
//完全背包问题,可转化为多重背包问题
//难度在于求 最小费用
//样例通过,提交AC。2019-1-1 19:37
#include <stdio.h>
#include <string.h>
int w[15],c[15],s[15],f[15][110];
int min(int a,int b){
return a<b?a:b;
}
int main(){
int n=10,m,i,j,k;
memset(f,127,sizeof(f)),f[0][0]=0;//此处写成 memset(f,127,sizeof(127)),f[0][0]=0; 昏招
for(i=1;i<=n;i++)
scanf("%d",&c[i]),w[i]=i;
scanf("%d",&m);
for(i=1;i<=n;i++)
s[i]=m/w[i];//转化为多重背包
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)//此处写成 for(j=1;j<=m;j++)
for(k=0;k<=s[i];k++)
if(j>=k*w[i])
f[i][j]=min(f[i][j],f[i-1][j-k*w[i]]+k*c[i]);//此处写成 f[i][j]=min(f[i][j],f[i-1][j-k*w[i]]+c[i]); 也是昏招
printf("%d\n",f[n][m]);
return 0;
}
6.找啊找啊找gf
//P1509 找啊找啊找GF
//在线测评地址https://www.luogu.org/problemnew/show/P1509
//https://www.luogu.org/problemnew/solution/P1509此文不仅原理讲得好,代码也写得棒
//P1509 找啊找啊找GF
//在线测评地址https://www.luogu.org/problemnew/show/P1509
//开两个动归数组dpNum[][][]数量,dpTime[][][]时间 [n][rmb][rp]
//“保证MM数量的情况下花费的最少总时间”此句对解题十分关键
//数量是第一,在保证数量的情况下,处理总时间
//01背包
//此文https://blog.csdn.net/legan/article/details/8888101三维数组写得好,就是本人要找的,学习了。
//样例通过,提交AC。2019-1-2
#include <stdio.h>
#include <string.h>
int dpNum[105][105][105],dpTime[105][105][105];
int rmb[105],rp[105],time[105];
int min(int a,int b){
return a<b?a:b;
}
int main(){
int i,j,k,n,m,r;
memset(dpNum,0,sizeof(dpNum)),memset(dpTime,0,sizeof(dpTime));
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d%d%d",&rmb[i],&rp[i],&time[i]);
scanf("%d%d",&m,&r);
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)
for(k=0;k<=r;k++){
dpNum[i][j][k]=dpNum[i-1][j][k];//写错位置,写到if之内//此句关键
dpTime[i][j][k]=dpTime[i-1][j][k];//写错位置,写到if之内//此句关键
if(j>=rmb[i]&&k>=rp[i]){//同时满足
if(dpNum[i][j][k]<dpNum[i-1][j-rmb[i]][k-rp[i]]+1){
dpNum[i][j][k]=dpNum[i-1][j-rmb[i]][k-rp[i]]+1;
dpTime[i][j][k]=dpTime[i-1][j-rmb[i]][k-rp[i]]+time[i];
}else if(dpNum[i][j][k]==dpNum[i-1][j-rmb[i]][k-rp[i]]+1)//此处写成else if(dpNum[i][j][k]=dpNum[i-1][j-rmb[i]][k-rp[i]]+1) 昏招//保证MM数量的情况下花费的最少总时间
dpTime[i][j][k]=min(dpTime[i][j][k],dpTime[i-1][j-rmb[i]][k-rp[i]]+time[i]);
}
}
printf("%d\n",dpTime[n][m][r]);
return 0;
}
dfs
7.n皇后
//2194 N皇后
//在线测评地址http://codevs.cn/problem/2194/
//算法:深搜+回溯
//测试了,感觉12或13有超时嫌疑
//样例通过,提交,竟然AC,好吧,那么就不优化了。2019-1-2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int a[20],cnt=0,n,vis[20];//a[i]=j,i代表行,j代表列;cnt代表解的总数
void dfs(int step){
int i,j,k,flag;
if(step==n+1){
cnt++;
if(cnt<=3){
printf("%d",a[1]);
for(k=2;k<=n;k++)printf(" %d",a[k]);
printf("\n");
}
return;
}
for(i=1;i<=n;i++)
if(vis[i]==0){
flag=0;
for(j=1;j<=step-1;j++)
if(abs(i-a[j])==abs(step-j)){//此处写成if(abs(a[i]-a[j])==abs(i-j))//对角线 判定
flag=1;
break;
}
if(flag==0){
vis[i]=1;
a[step]=i;
dfs(step+1);
vis[i]=0;//回溯
}
}
}
int main(){
memset(vis,0,sizeof(vis));
scanf("%d",&n);
dfs(1);
printf("%d\n",cnt);
return 0;
}
终于AC了一周的内容,甚是高兴,一个好的开始。2019-1-2