总目录详见https://blog.youkuaiyun.com/mrcrack/article/details/84471041
做题原则,找不到测评地址的题不做。2018-11-28
重走长征路---OI每周刷题记录---10月5日 2013
本周共计15题。
测评地址:
高精度
1.阶乘统计2 //在线测评地址http://codevs.cn/problem/2172/
结构体快排
2.忠诚 //在线测评地址http://codevs.cn/problem/2173/
模拟
3.Dinner //在线测评地址https://vjudge.net/problem/NBUT-1217
4.越野跑 //在线测评地址http://codevs.cn/problem/2151/
5.铺地毯 //在线测评地址https://www.luogu.org/problemnew/show/P1003
6.Time //在线测评地址https://vjudge.net/problem/NBUT-1219
7.乒乓球 //在线测评地址https://www.luogu.org/problemnew/show/P1042
8.Vigenère密码 //在线测评地址https://www.luogu.org/problemnew/show/P1079
dfs
9.滑雪 //在线测评地址https://www.luogu.org/problemnew/show/P1434
背包dp
10.采药 //在线测评地址https://www.luogu.org/problemnew/show/P1048
11.强壮的zzw //在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1287
12.金明的预算 //在线测评地址https://www.luogu.org/problemnew/show/P1064
dp
13.等差数列 //在线测评地址http://codevs.cn/problem/2205/
14.数字组合 //在线测评地址http://codevs.cn/problem/2210/
区间dp
15.合并沙子 //在线测评网站http://codevs.cn/problem/1382/
题解:
高精度
1.阶乘统计2
//2172 阶乘统计第二季
//在线测评地址http://codevs.cn/problem/2172/
//看了数据范围1<=n<=1400000,要想AC,只能采用O(n)的算法
//因1<=k<=10,数据还得采用long long
//基本思路,遇到的数 若能被10整除,要一直处下去
//接着统计其中5的因子的个数
//接着继续统计其中2的因子的个数
//剩下的数,就可以乘进结果中,同时模以10^k
//最后,再将5与2配对,再对剩下的5或2进行处理
//样例通过,测试了1400000 10速度很快
//提交AC。2019-1-13 9:28
#include <stdio.h>
#include <string.h>
#define LL long long
int stack[15],top=0;//用来打印结果
int main(){
LL ans=1,mod=1;//之前写成int mod=1;
int n,k,i,m,cnt_5=0,cnt_2=0;
memset(stack,0,sizeof(stack));
scanf("%d%d",&n,&k);
for(i=1;i<=k;i++)mod*=10;
for(i=1;i<=n;i++){
m=i;
while(m%10==0)m/=10;
while(m%5==0)m/=5,cnt_5++;
while(m%2==0)m/=2,cnt_2++;
ans=(ans*m)%mod;
}
if(cnt_5>=cnt_2){//5与2进行配对处理
for(i=1;i<=cnt_5-cnt_2;i++)
ans=(ans*5)%mod;
}else{
for(i=1;i<=cnt_2-cnt_5;i++)
ans=(ans*2)%mod;
}
while(ans){
stack[++top]=ans%10;
ans/=10;
}
for(i=k;i>=1;i--)printf("%d",stack[i]);//用0补齐
return 0;
}
结构体快排
2.忠诚
//2173 忠诚
//在线测评地址http://codevs.cn/problem/2173/
//结构体,快排
//决定采用C++,用sort函数
//算法的时间复杂度达到O(n*m),没什么把握
//提交,测试点4RE,8WA,测试点5,10TLE 得分60
//以下为60分代码。2018-12-26
//还是要向AC迈进,翻看他人代码,发现线段树还能这么用,长见识了。
//开始编码,回到C代码。
//在query函数中花了些功夫, a=INF,b=INF a=query(2*k,left,right) b=query(2*k+1,left,right) return min(a,b);
//自我感觉还不错,独立完成,提交AC。2018-12-26
#include <stdio.h>
#define maxn 100100
#define INF 999999999
struct node{
int left,right,v;//v存储当前区间的最小值
}q[4*maxn];
int min(int a,int b){
return a<b?a:b;
}
void build(int k,int left,int right){
int mid=(left+right)/2;
q[k].left=left,q[k].right=right;
if(left==right){
scanf("%d",&q[k].v);
return;
}
build(2*k,left,mid);
build(2*k+1,mid+1,right);
q[k].v=min(q[2*k].v,q[2*k+1].v);
}
int query(int k,int left,int right){
int mid=(q[k].left+q[k].right)/2,a=INF,b=INF;
if(left<=q[k].left&&q[k].right<=right)
return q[k].v;
if(left<=mid)a=query(2*k,left,right);
if(mid+1<=right)b=query(2*k+1,left,right);
return min(a,b);
}
int main(){
int m,n,i,left,right;
scanf("%d%d",&m,&n);
build(1,1,m);
while(n--){
scanf("%d%d",&left,&right);
printf("%d ",query(1,left,right));
}
return 0;
}
//2173 忠诚
//在线测评地址http://codevs.cn/problem/2173/
//结构体,快排
//决定采用C++,用sort函数
//算法的时间复杂度达到O(n*m),没什么把握
//提交,测试点4RE,8WA,测试点5,10TLE 得分60
//以下为60分代码。2018-12-26
#include <cstdio>
#include <algorithm>
#define maxn 100100
using namespace std;
struct node{
int pos;
int v;
}q[maxn];
int cmp(const struct node &a,const struct node &b){
return a.v<=b.v;
}
int main(){
int m,n,i,left,right;
scanf("%d%d",&m,&n);
for(i=1;i<=m;i++)scanf("%d",&q[i].v),q[i].pos=i;
sort(q+1,q+n+1,cmp);
while(n--){
scanf("%d%d",&left,&right);
for(i=1;i<=m;i++)
if(left<=q[i].pos&&q[i].pos<=right){
printf("%d ",q[i].v);
break;
}
}
return 0;
}
模拟
3.Dinner
//Dinner
//在线测评地址https://vjudge.net/problem/NBUT-1217
//ACM方式提交,要特别注意输出格式
//样例通过,提交AC。2018-12-27
#include <stdio.h>
#include <string.h>
char table[][15]={"bowl","knife","fork","chopsticks"};
char s[15];
int main(){
int n,i,k;
while(scanf("%d",&n)!=EOF){
k=0;
while(n--){
scanf("%s",s);
for(i=0;i<4;i++)
if(strcmp(s,table[i])==0){
k++;
if(k==1)printf("%s",s);
else printf(" %s",s);
}
}
printf("\n");
}
return 0;
}
4.越野跑
//2151 越野跑
//在线测评地址http://codevs.cn/problem/2151/
//样例通过,提交AC。2018-12-27
#include <stdio.h>
int main(){
int m,t,u,f,d,cnt=0,u_t,f_t,d_t,n=0;
char cmd[5];
scanf("%d%d%d%d%d",&m,&t,&u,&f,&d);
u_t=d_t=u+d,f_t=f+f;
while(t--){
scanf("%s",cmd);
switch(cmd[0]){
case 'u':
n+=u_t;
break;
case 'f':
n+=f_t;
break;
case 'd':
n+=d_t;
break;
}
cnt++;
if(n>m)break;//此处写成 if(n<m)break; 昏招
}
if(n>m)printf("%d\n",cnt-1);//需扣除多计算的一段
else printf("%d\n",cnt); //若在提供的m段已用完。
return 0;
}
5.铺地毯
//P1003 铺地毯
//在线测评地址https://www.luogu.org/problemnew/show/P1003
//样例通过,提交AC。2018-12-27 17:30
#include <stdio.h>
#define maxn 10100
int a[maxn],b[maxn],g[maxn],k[maxn];
int main(){
int n,i,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d%d%d%d",&a[i],&b[i],&g[i],&k[i]);
scanf("%d%d",&x,&y);
for(i=n;i>=1;i--)
if(a[i]<=x&&x<=a[i]+g[i]&&b[i]<=y&&y<=b[i]+k[i]){
printf("%d\n",i);
break;
}
if(i==0)printf("-1\n");//没找到地毯
return 0;
}
6.Time
//Time NBUT - 1219
//在线测评地址https://vjudge.net/problem/NBUT-1219
//该题的核心是,each digit is described by 3*3 characters
//该题思路,将每个数字用二维字符数组表示
//再将用到的数字打印即可。
//编写一个数字,测试一个数字,效果如下图
//样例通过,提交Compilation error。基本可以确定是,代码中不能有中文注释,2019-1-12 21:46
//那么,删除代码中的中文注释,提交AC。NBUT真是一个奇葩的OJ。2019-1-12 21:50
//总的来讲,构造数字对应的字符串比较耗时。
#include <stdio.h>
char d[12][5][5]={{" _ ","| |","|_|"},{" "," |"," |"},{" _ "," _|","|_ "},{" _ "," _|"," _|"},{" ","|_|"," |"},{" _ ","|_ "," _|"},{" _ ","|_ ","|_|"},{" _ "," |"," |"},{" _ ","|_|","|_|"},{" _ ","|_|"," _|"}};
int a[5];
int main(){
int i,j,k=0;
while(scanf("%d",&a[k])!=EOF){
k++;
if(k==4){
for(i=0;i<3;i++){//i表示行
for(j=0;j<4;j++)//j表示第几个数字
printf("%s",d[a[j]][i]);
printf("\n");
}
k=0;
}
}
return 0;
}
7.乒乓球
//P1042 乒乓球
//NOIP 2003 普及组
//在线测评地址https://www.luogu.org/problemnew/show/P1042
//25*2500 int不会溢出
//样例通过,提交AC。真是高兴,印象中,以前这个题目编得很累,今日真轻松。2018-12-27
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char s[30];
int cnt=0;
struct node{
int W;
int L;
}q[30*2500],p[30*2500];
void print(int n,int cnt){//n表示11分,或21分;
int i,W,L;//W,L存储已逝去的分数
memcpy(p,q,sizeof(q));
W=0,L=0;
for(i=1;i<=cnt;i++)
if((p[i].W-W>=n||p[i].L-L>=n)&&abs(p[i].W-W-(p[i].L-L))>=2){
printf("%d:%d\n",p[i].W-W,p[i].L-L);
W+=p[i].W-W,L+=p[i].L-L;//此处写成W+=p[i].W,L+=p[i].L;//此行很关键,记录消耗掉的局比分
}
if(p[cnt].W-W==0&&p[cnt].L-L==0)printf("0:0\n"); //打印0:0特判
else if(p[cnt].W-W>0||p[cnt].L-L>0)printf("%d:%d\n",p[cnt].W-W,p[cnt].L-L);
}
int main(){
int len,flag=0,i;
memset(q,0,sizeof(q));
while(scanf("%s",s)!=EOF){//读取数据
len=strlen(s);
for(i=0;i<len;i++)
if(s[i]=='E'){
flag=1;
break;
}else{
cnt++;
if(s[i]=='W'){
q[cnt].W+=q[cnt-1].W+1;
q[cnt].L+=q[cnt-1].L;
}else{
q[cnt].W+=q[cnt-1].W;
q[cnt].L+=q[cnt-1].L+1;
}
}
if(flag==1)break;
}
print(11,cnt);
printf("\n");
print(21,cnt);
}
8.Vigenère密码
//P1079 Vigenère 密码
//NOIP 2012 提高组
//在线测评地址https://www.luogu.org/problemnew/show/P1079
//编编发现不对,编成 明文+密钥=密文
//而题意要求 密文+密钥=>明文
//重新编写,关键是生成一套密码本,准备开一个数组f[i][j]=k i密文,j密码, k明文
//样例通过,提交AC。2018-12-29
//自我感觉,此种编码,在考试中,成功率更高,此次编写,该题的编码与以往有了很大不同。
#include <stdio.h>
#include <string.h>
int f[30][30];
char key[110],secret[1100];
int main(){
int len_k,len_s,i,j,k;
char c;
for(k=0;k<26;k++)
for(j=0;j<26;j++)
f[(k+j)%26][j]=k;//生成密码本 f[i][j]=k i密文,j密码, k明文
scanf("%s%s",key,secret);
len_k=strlen(key),len_s=strlen(secret);
for(i=0;i<len_k;i++)
if('A'<=key[i]&&key[i]<='Z')//将大写转成小写
key[i]='a'+key[i]-'A';
for(i=0;i<len_s;i++){
if('A'<=secret[i]&&secret[i]<='Z')//大写字母
c='A'+f[secret[i]-'A'][key[i%len_k]-'a'];
else//小写字母
c='a'+f[secret[i]-'a'][key[i%len_k]-'a'];
printf("%c",c);
}
return 0;
}
dfs
9.滑雪
//P1434 [SHOI2002]滑雪
//在线测评地址https://www.luogu.org/problemnew/show/P1434
//纯深搜dfs从数据范围看,必定超时
//采用记忆化搜索
//滑雪最大长度100*100=10^4 故int 足够
//样例通过,提交,测试点2 TLE。90分,自己独立编写,一次就拿到90分,高兴。
//以下为90分代码。2018-12-28 20:54
//翻看之前的代码,发现写了个假的记忆化搜索,
//f[x][y]=len;//漏了此句,惭愧。2018-12-28 21:10
//提交AC。2018-12-28 21:12
//以下为AC代码。
#include <stdio.h>
#include <string.h>
#define maxn 110
int a[110][110],f[110][110];//f[i][j]从i,j出发滑雪最长距离
int next[][2]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右
int r,c;
int max(int a,int b){
return a>b?a:b;
}
int dfs(int x,int y){
int i,nx,ny,len=1,cnt=1;
if(f[x][y])return f[x][y];//已计算过
for(i=0;i<4;i++){
nx=x+next[i][0],ny=y+next[i][1];
if(1<=nx&&nx<=r&&1<=ny&&ny<=c&&a[x][y]>a[nx][ny]){
if(f[nx][ny])cnt=f[nx][ny]+1;//此处写成 cnt+=f[nx][ny];
else cnt=dfs(nx,ny)+1;//此处写成 cnt+=dfs(nx,ny);
}
len=max(len,cnt);
}
f[x][y]=len;//漏了此句,惭愧。2018-12-28 21:10
return len;
}
int main(){
int i,j,len=1;
memset(f,0,sizeof(f));
scanf("%d%d",&r,&c);
for(i=1;i<=r;i++)
for(j=1;j<=c;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=r;i++)
for(j=1;j<=c;j++){
len=max(len,dfs(i,j));
}
printf("%d\n",len);
return 0;
}
//P1434 [SHOI2002]滑雪
//在线测评地址https://www.luogu.org/problemnew/show/P1434
//纯深搜dfs从数据范围看,必定超时
//采用记忆化搜索
//滑雪最大长度100*100=10^4 故int 足够
//样例通过,提交,测试点2 TLE。90分,自己独立编写,一次就拿到90分,高兴。
//以下为90分代码。2018-12-28 20:54
#include <stdio.h>
#include <string.h>
#define maxn 110
int a[110][110],f[110][110];//f[i][j]从i,j出发滑雪最长距离
int next[][2]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右
int r,c;
int max(int a,int b){
return a>b?a:b;
}
int dfs(int x,int y){
int i,nx,ny,len=1,cnt=1;
if(f[x][y])return f[x][y];//已计算过
for(i=0;i<4;i++){
nx=x+next[i][0],ny=y+next[i][1];
if(1<=nx&&nx<=r&&1<=ny&&ny<=c&&a[x][y]>a[nx][ny]){
if(f[nx][ny])cnt=f[nx][ny]+1;//此处写成 cnt+=f[nx][ny];
else cnt=dfs(nx,ny)+1;//此处写成 cnt+=dfs(nx,ny);
}
len=max(len,cnt);
}
return len;
}
int main(){
int i,j,len=1;
memset(f,0,sizeof(f));
scanf("%d%d",&r,&c);
for(i=1;i<=r;i++)
for(j=1;j<=c;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=r;i++)
for(j=1;j<=c;j++){
len=max(len,dfs(i,j));
}
printf("%d\n",len);
return 0;
}
背包dp
10.采药
//P1048 采药
//在线测评地址https://www.luogu.org/problemnew/show/P1048
//01背包
//样例通过,提交AC。2018-12-29
#include <stdio.h>
#include <string.h>
int t[110],c[110],f[110][1100];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int T,M,i,j;
memset(f,0,sizeof(f));
scanf("%d%d",&T,&M);
for(i=1;i<=M;i++)
scanf("%d%d",&t[i],&c[i]);
for(i=1;i<=M;i++)
for(j=1;j<=T;j++)
if(j<t[i])f[i][j]=f[i-1][j];
else f[i][j]=max(f[i-1][j],f[i-1][j-t[i]]+c[i]);
printf("%d\n",f[M][T]);
}
11.强壮的zzw
//1287: 强壮的ZZW
//在线测评地址http://218.5.5.242:9018/JudgeOnline/problem.php?id=1287
//01背包,特别之处,二维数组要爆内存f[4100][15100]
//4100*15100*4/1024/1024=236M
//降维,采用一维数组f[15100]
//强度最大值100*4000=4*10^5 int不会溢出
//降维,需逆序计算
//样例通过,提交 运行错误。2019-1-12 20:33
//排查,发现 int v[maxn],d[maxn],f[15100];//此处写成 f[maxn]
//修改,提交AC。2019-1-12 20:36
#include <stdio.h>
#include <string.h>
#define maxn 4100
int v[maxn],d[maxn],f[15100];//此处写成 f[maxn]
int max(int a,int b){
return a>b?a:b;
}
int main(){
int N,S,i,j;
memset(f,0,sizeof(f));
scanf("%d%d",&N,&S);
for(i=1;i<=N;i++)scanf("%d%d",&v[i],&d[i]);
for(i=1;i<=N;i++)
for(j=S;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+d[i]);
printf("%d\n",f[S]);
return 0;
}
12.金明的预算
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
//准备考虑,主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行讨论
//修改,提交30分,发现更糟糕,测试点3-8,10WA。2019-1-13 21:16
//感觉是有问题的。以下为30分代码。
//想看答案,忍住了,心想,要是接下来的思路还有重大问题,再看解答。
//仔细想想,应该同时对 主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行选择
//大篇幅修改,提交AC.那个高兴啊,没有参考任何资料,一点一点的磨出,思维达到新高度。2019-1-14 8:19
//以下为AC代码。
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int n,m,i,j,d;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0)//主件
for(j=n;j>=v[i];j--){//在同一处话费,对 主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行选择
f[j]=max(f[j],f[j-v[i]]+v[i]*p[i]);
if(q[i][0]>=1&&j>=v[i]+v[q[i][1]])f[j]=max(f[j],f[j-v[i]-v[q[i][1]]]+v[i]*p[i]+v[q[i][1]]*p[q[i][1]]);
if(q[i][0]==2){
if(j>=v[i]+v[q[i][2]])
f[j]=max(f[j],f[j-v[i]-v[q[i][2]]]+v[i]*p[i]+v[q[i][2]]*p[q[i][2]]);
if(j>=v[i]+v[q[i][1]]+v[q[i][2]])
f[j]=max(f[j],f[j-v[i]-v[q[i][1]]-v[q[i][2]]]+v[i]*p[i]+v[q[i][1]]*p[q[i][1]]+v[q[i][2]]*p[q[i][2]]);
}
}
printf("%d\n",f[n]*10);
return 0;
}
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
//准备考虑,主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行讨论
//修改,提交30分,发现更糟糕,测试点3-8,10WA。2019-1-13 21:16
//感觉是有问题的。以下为30分代码。
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int main(){
int n,m,i,j,k,d,V,P;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0){//主件
V=v[i],P=v[i]*p[i];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
if(q[i][0]>=1){
V+=v[q[i][1]],P+=v[q[i][1]]*p[q[i][1]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
}
if(q[i][0]==2){
V=v[i]+v[q[i][2]],P=v[i]*p[i]+v[q[i][2]]*p[q[i][2]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
V=v[i]+v[q[i][1]]+v[q[i][2]],P=v[i]*p[i]+v[q[i][1]]*p[q[i][1]]+v[q[i][2]]*p[q[i][2]];
}
}
printf("%d\n",f[n]*10);
return 0;
}
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int main(){
int n,m,i,j,k,d,V,P;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0){//主件
for(k=0;k<=q[i][0];k++){
if(k==0)V=v[i],P=v[i]*p[i];
else V+=v[q[i][k]],P+=v[q[i][k]]*p[q[i][k]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
}
}
printf("%d\n",f[n]*10);
return 0;
}
dp
13.等差数列
//2205 等差数列
//在线测评地址http://codevs.cn/problem/2205/
//f[i][d]以a[i]为结尾,公差为d的等差数列个数,该题,极难想。
//看了他人代码,很快明白,但自己想,很困难。2018-12-26
//提交,30分,WA。
//ans=(ans+f[j][d]+1)%mod;//此句写成 ans=(ans+f[i][d])%mod;
//仔细想了想,f[i][d]还存在变数,但f[j][d]数据已经固化。
//修改,提交,AC。2018-12-26
#include <stdio.h>
#include <string.h>
#define mod 9901
int f[1100][2100],a[1100];
int main(){
int n,i,j,d,ans;
memset(f,0,sizeof(f));
scanf("%d",&n);
ans=n;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)
for(j=1;j<i;j++){
d=a[i]-a[j]+1000;//1000的目的,保证d>=0
f[i][d]=(f[i][d]+f[j][d]+1)%mod;
ans=(ans+f[j][d]+1)%mod;//此句写成 ans=(ans+f[i][d])%mod;
}
printf("%d\n",ans);
return 0;
}
14.数字组合
//2210 数字组合
//在线测评地址http://codevs.cn/problem/2210/
//上动归,找不着北
//绝不放弃,试试深搜dfs 1<N<100应该能拿些分
//保险起见,统计个数,采用long long
//样例通过,提交AC。不敢相信,dfs 竟然AC了。
//该题核心,找数据,一路向前,绝不回头。以下两句极为核心
//for(i=start;i<=n;i++)
//dfs(i+1);
//2018-12-26 19:28
#include <stdio.h>
#include <string.h>
#define LL long long
int n,m;
int a[110],vis[110],sum=0,b[110];
LL cnt=0;
void dfs(int start){
int i,j;
if(sum>m)return;//剪枝
if(sum==m){
cnt++;
return;
}
for(i=start;i<=n;i++)//此处写成for(i=1;i<=n;i++) 查了好久
if(vis[i]==0){
vis[i]=1;
sum+=a[i];
dfs(i+1);//此处写成dfs(start+1); 调了好久//此处写成 dfs(sum+a[i]);
sum-=a[i];
vis[i]=0;//回溯
}
}
int main(){
int i;
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
dfs(1);
printf("%lld\n",cnt);
return 0;
}
区间dp
15.合并沙子
//1382 沙子合并
//在线测评网站http://codevs.cn/problem/1382/
//f[i][j] i->j之间的 最小和
//开一个前缀和b[i] 1->i的和
//f[i][i]=0;//此处真是,神来之笔
//最小的中间和的动归,完全是独立想出,高兴。
//样例通过,提交AC。2018-12-21
#include <stdio.h>
#include <string.h>
#define maxn 310
int a[maxn],f[maxn][maxn],b[maxn];
int min(int a,int b){
return a<b?a:b;
}
int main(){
int i,j,n,k;
scanf("%d",&n);
memset(f,127,sizeof(f)),b[0]=0;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i][i]=0;//此处真是,神来之笔
b[i]+=b[i-1]+a[i];
}
if(n==1){//特判,省得添堵
printf("%d\n",a[n]);
return 0;
}
for(k=1;k<=n-1;k++)
for(i=1;i<=n;i++)
if(i+k<=n)
for(j=i;j<=i+k;j++)
f[i][i+k]=min(f[i][i+k],f[i][j]+f[j+1][i+k]+b[i+k]-b[i-1]);
printf("%d\n",f[1][n]);
return 0;
}
2019-1-14 8:23 AC该周内容。