天天看點

重走長征路---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 <stdio.h>

#include <string.h>

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<a[i+1][j-2])b=a[i+1][j-2],k=j-2;

            if(j-1>=1&&b<a[i+1][j-1])b=a[i+1][j-1],k=j-1;

            if(b<a[i+1][j])b=a[i+1][j],k=j;

            if(j+1<=W&&b<a[i+1][j+1])b=a[i+1][j+1],k=j+1;

            if(j+2<=W&&b<a[i+1][j+2])b=a[i+1][j+2],k=j+2;

            a[i][j]+=b,p[i][j]=k;

        }

    }

    pos=(W+1)/2;

    printf("%d\n",a[0][pos]);

    for(i=0;i<end;i++){//此處寫成for(i=begin-1;i<end;i++)//此處寫成 for(i=0;i<t;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 <stdio.h>

#include <string.h>

int n,a[210],dp1[210][210],dp2[210][210],sum[210];

int min(int a,int b){

    return a<b?a:b;

}

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<n;k++)

        for(i=1;i<=2*n;i++)//此處寫成 for(i=1;i<=n;i++)

            for(j=i;j<i+k;j++)//此處寫成 for(j=i;j<=i+k;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 <stdio.h>

#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<right){

                mid=(left+right)/2;

                if(f[mid]<h)right=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 <stdio.h>

#include <string.h>

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<n;k++)//此處寫成 for(k=2;k<n;k++),查了會 

        for(i=1;i<=2*n;i++)

            for(j=i;j<i+k;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 <stdio.h>

#include <string.h>

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<d[i])

            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 <stdio.h>

#include <string.h>

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<sum){

        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 <stdio.h>

#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 <cstdio>

#include <algorithm>

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 <stdio.h>

#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<M;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<b[i][0])now=b[i][103]-1;//此處寫成now=b[i][b[i][103]-1];//無樓梯房間在所有有樓梯房間的在最開始

            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<b[i][103];j++)

                    if(b[i][j]<start&&start<b[i][j+1]){

                        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<b[i][103];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 <stdio.h>

#include <string.h>

#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 <stdio.h>

#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 <stdio.h>

#include <string.h>

#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 <stdio.h>

#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 <stdio.h>

#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 <stdio.h>

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 <stdio.h>

#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 <stdio.h>

#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<i;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 <stdio.h>

#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 <stdio.h>

#include <string.h>

#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 <stdio.h>

#include <string.h>

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 <stdio.h>

#include <string.h>

#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 <stdio.h>

#include <string.h>

#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<k;j++)sum[i][j]=color[j];

        q[i]=consume;

    }

    now=0;

    for(i=1;i<=n;i++)

        if(q[i]<=p){

            for(j=0;j<k;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 <stdio.h>

#include <string.h>

#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<t;i++)

            if(q[i]==a)break;

        if(i==t){//i==t發生在,沒找到該單詞

            cnt++;

            if(t-h<m)//加入記憶體

                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 <stdio.h>

#include <string.h>

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<len){

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

#include <algorithm>

#include <cstring>//漏了此頭檔案

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<b.seq;

    return a.score>b.score;//此處寫成return a.score<b.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

//該題難在,思考出上述模拟過程 

//需簡單測試,負數的除模運算。

//-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 <stdio.h>

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 <stdio.h>

#include <math.h>

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

}