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

总目录详见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该周内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值