1. 程式人生 > >NOIP2013普及組 題解

NOIP2013普及組 題解

T1  計數問題

題目描述

試計算在區間 1 到 n 的所有整數中,數字 x(0 ≤ x ≤ 9)共出現了多少次?例如,在 1

到 11 中,即在 1、2、3、4、5、6、7、8、9、10、11 中,數字 1 出現了 4 次。

輸入輸出格式

輸入格式:

輸入檔名為 count.in。

輸入共 1 行,包含 2 個整數 n、x,之間用一個空格隔開。

輸出格式:

輸出檔名為 count.out。

輸出共 1 行,包含一個整數,表示 x 出現的次數。

輸入輸出樣例

輸入樣例#1:
11 1
輸出樣例#1:
4

說明

對於 100%的資料,1≤ n ≤ 1,000,000,0 ≤ x ≤ 9。

並沒有難度,列舉每個數的每一位就行

#include<cstdio>
#include<iostream>
using namespace std;
int main(){
    int n,x;
    cin>>n>>x;
    int i,c=0;
    for(i=1;i<=n;i++){
        int a=i;
        while(a!=0){
            if(a%10==x)c++;
            a/=10;
        }
    }
    cout<<c;
    return 0;
}

T2 表示式求值

題目描述

給定一個只包含加法和乘法的算術表示式,請你程式設計計算表示式的值。

輸入輸出格式

輸入格式:

輸入檔案為 expr.in。

輸入僅有一行,為需要你計算的表示式,表示式中只包含數字、加法運算子“+”和乘

法運算子“*”,且沒有括號,所有參與運算的數字均為 0 到 2^31-1 之間的整數。輸入資料保

證這一行只有 0~ 9、+、*這 12 種字元。

輸出格式:

輸出檔名為 expr.out。

輸出只有一行,包含一個整數,表示這個表示式的值。注意:當答案長度多於 4 位時,

請只輸出最後 4 位,前導 0 不輸出。

輸入輸出樣例

輸入樣例#1:
1+1*3+4
輸出樣例#1:
8
輸入樣例#2:

1+1234567890*1
輸出樣例#2:
7891
輸入樣例#3:
1+1000000003*1
輸出樣例#3:
4

說明

對於 30%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100;

對於 80%的資料,0≤表示式中加法運算子和乘法運算子的總數≤1000;

對於 100%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100000。

/*NOIP2013普及組t2 洛谷P1981 表示式求值*/
/**/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
char last;
char c;
int x=0;
int a=0,b=1;
int sum=0;
int main(){
    int i,j;
    bool flag=1;
    do{
        if(cin>>c);
        else{
            flag=0;
            c='+';//相當於在整個串最後補個+號,以完成全部運算
        }
        if(c>='0' && c<='9')x=x*10+c-'0';//讀取數
        else{
            a=x;//如果讀到的不是數字,把之前讀到的數存起來
            x=0;//初始化
        }
        if(c=='*'){//處理乘號,方法是先記下這個數,下次讀到乘號再計算
            last=1;
            b=(a*b)%10000;//有連續乘號時,累乘
        }
        if(c=='+'){
            if(last){//上一個是乘號的情況
                a=(a*b)%10000;
                sum=(sum+a)%10000;
                b=1;
                last=0;
            }
            else sum+=a;//上一個是加號的情況
        }
        
    }while(flag==1);
    printf("%d",sum%10000);
    return 0;
}

T3 小朋友的數字

題目描述

有 n 個小朋友排成一列。每個小朋友手上都有一個數字,這個數字可正可負。規定每個

小朋友的特徵值等於排在他前面(包括他本人)的小朋友中連續若干個(最少有一個)小朋

友手上的數字之和的最大值。

作為這些小朋友的老師,你需要給每個小朋友一個分數,分數是這樣規定的:第一個小

朋友的分數是他的特徵值,其它小朋友的分數為排在他前面的所有小朋友中(不包括他本人),

小朋友分數加上其特徵值的最大值。

請計算所有小朋友分數的最大值,輸出時保持最大值的符號,將其絕對值對 p 取模後

輸出。

輸入輸出格式

輸入格式:

輸入檔案為 number.in。

第一行包含兩個正整數 n、p,之間用一個空格隔開。

第二行包含 n 個數,每兩個整數之間用一個空格隔開,表示每個小朋友手上的數字。

輸出格式:

輸出檔名為 number.out。

輸出只有一行,包含一個整數,表示最大分數對 p 取模的結果。

輸入輸出樣例

輸入樣例#1:
5 997 
1 2 3 4 5 
輸出樣例#1:
21
輸入樣例#2:
5 7 
-1 -1 -1 -1 -1 
輸出樣例#2:
-1

說明

Case 1:

小朋友的特徵值分別為 1、3、6、10、15,分數分別為 1、2、5、11、21,最大值 21

對 997 的模是 21。

Case 2:

小朋友的特徵值分別為-1、-1、-1、-1、-1,分數分別為-1、-2、-2、-2、-2,最大值

-1 對 7 的模為-1,輸出-1。

對於 50%的資料,1 ≤ n ≤ 1,000,1 ≤ p ≤ 1,000所有數字的絕對值不超過 1000;

對於 100%的資料,1 ≤ n ≤ 1,000,000,1 ≤ p ≤ 10^9,其他數字的絕對值均不超過 10^9。

這上百萬個小朋友的老師還真是累啊…… 完全可以讀一個算一個,每次把新算出的數值和之前儲存的最大值比較,得到新的最大值。 特徵值和分數都這麼處理
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const long long inf=1000000005;
int n,p,a[1000500];

long long su[1000500]={0};//特徵值,也可以不要陣列 
long long scoremx=-inf;//前排最大分數 
long long dmx=-inf;//分數加特徵值的最大值 
long long ans=-inf; 
int sum1(){//計算特徵值。 
    int i,j;
    long long s=0;
    long long mx=-inf;
    for(i=1;i<=n;i++){
        if(s+a[i]>mx)mx=s+a[i];
        su[i]=mx;
        if(s+a[i]>0) s+=a[i];
        else s=0;
    }
    //
    for(i=1;i<=n;i++){
        su[i]%=p<<1;//防止資料過大 
        //p<<1可以避免mod時的誤差(如果是讀一個算一個,資料不會超限制 ,而一次算完的做法就有必要處理一下資料了)
    }
    return 0;
}
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    int i,j;
    scanf("%d%d",&n,&p);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    sum1();
    long long score;
//1 處理第一個資料 
    scoremx=su[1];
    score=su[1];
    dmx=score+su[1];
//end
    for(i=2;i<=n;i++){
        score=dmx;
        if(dmx>scoremx)scoremx=dmx;
        if(su[i]+score>dmx)dmx=su[i]+score;
    }
    printf("%d",scoremx%p);
    return 0;
}

T4-車站分級

題目描述

一條單向的鐵路線上,依次有編號為 1, 2, …, n 的 n 個火車站。每個火車站都有一個級

別,最低為 1 級。現有若干趟車次在這條線路上行駛,每一趟都滿足如下要求:如果這趟車

次停靠了火車站 x,則始發站、終點站之間所有級別大於等於火車站 x 的都必須停靠。(注

意:起始站和終點站自然也算作事先已知需要停靠的站點)

例如,下表是 5 趟車次的執行情況。其中,前 4 趟車次均滿足要求,而第 5 趟車次由於

停靠了 3 號火車站(2 級)卻未停靠途經的 6 號火車站(亦為 2 級)而不滿足要求。

現有 m 趟車次的執行情況(全部滿足要求),試推算這 n 個火車站至少分為幾個不同的

級別。

輸入輸出格式

輸入格式:

輸入檔案為 level.in。

第一行包含 2 個正整數 n, m,用一個空格隔開。

第 i + 1 行(1 ≤ i ≤ m)中,首先是一個正整數 si(2 ≤ si

≤ n),表示第 i 趟車次有 si 個停

靠站;接下來有 si個正整數,表示所有停靠站的編號,從小到大排列。每兩個數之間用一個

空格隔開。輸入保證所有的車次都滿足要求。

輸出格式:

輸出檔案為 level.out。

輸出只有一行,包含一個正整數,即 n 個火車站最少劃分的級別數。

輸入輸出樣例

輸入樣例#1:
Case 1:
9 2 
4 1 3 5 6 
3 3 5 6 

Case 2:
9 3 
4 1 3 5 6 
3 3 5 6 
3 1 5 9 
輸出樣例#1:
Case 1:
2

Case 2:
3

說明

對於 20%的資料,1 ≤ n, m ≤ 10;

對於 50%的資料,1 ≤ n, m ≤ 100;

對於 100%的資料,1 ≤ n, m ≤ 1000。

如果這趟車次停靠了火車站 x,則始發站、終點站之間所有級別大於等於火車站 x 的都必須停靠,所以一趟車從始發站到終點站之間,沒停的站級別都低於停了的站。

在低階站和高階站之間連線,構成AOV網,利用拓撲排序即可知道總共有多少級車站

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int a;//[第i趟車次的停靠站數]
int s[2000];//[第i趟車次停靠的站] 
int mp[1200][1200]={0};
int book[1200];
int r[1200],c[1200]; //入度出度 
int st[1200];
int ans=0;
void rd(){
    scanf("%d%d",&n,&m);
    int i,j,k;
    for(i=1;i<=m;i++){
        memset(book,0,sizeof(book));
        scanf("%d",&a);
        for(j=1;j<=a;j++){
            scanf("%d",&s[j]);
            book[s[j]]=1;
        }
        for(k=s[1];k<=s[a];k++)//遍歷從始發站到終點站
        {
            if(!book[k])
                for(j=1;j<=a;j++)
                if(!mp[k][s[j]])//從低階連到高階可過,從高階連到低階無誤但超時 
                {
                 mp[k][s[j]]=1;//從低階站到高階站連線 
                 r[s[j]]++;}//入度++ 
        }
        
    }
}
int main(){
//    freopen("level.in","r",stdin);
//    freopen("level.out","w",stdout);
    rd();
    int i,j;
    int top=0;
    memset(book,0,sizeof(book));
    while(1){//拓撲排序 
        ans++;//迴圈次數即為總級數 
        top=0;
        for(i=1;i<=n;i++)
            if(!r[i] && !book[i])//所有沒有入度且之前沒處理過的點,都是同一級別的 
            {
                top++;
                st[top]=i;//入站 
                book[i]=1;//標記為已處理 
            }
            
        if(!top)break;//棧為空,說明所有點都排好序了 
        for(j=1;j<=n;j++)
          for(i=1;i<=top;i++){
              if(mp[st[i]][j]){
                  mp[st[i]][j]=0;
                  r[j]--;
              }
          }    
        if(!top)break;
    }    
    
    printf("%d",ans-1);
    
    
    return 0;
}