1. 程式人生 > >重走長征路---OI每週刷題記錄---10月5日 2013

重走長征路---OI每週刷題記錄---10月5日 2013

總目錄詳見https://blog.csdn.net/mrcrack/article/details/84471041

做題原則,找不到測評地址的題不做。2018-11-28

重走長征路---OI每週刷題記錄---10月5日  2013

階乘統計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;
}

模擬

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;
}

越野跑

//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;
}

鋪地毯

//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;
}

Time

乒乓球

//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);
}

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

滑雪

//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;

採藥

//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]);
}

強壯的zzw 金明的預算 揹包dp

dp

等差數列

//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;
}

數字組合

//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

合併沙子

//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;
}