1. 程式人生 > >NOIP2010 普及組 蒟蒻的題解報告

NOIP2010 普及組 蒟蒻的題解報告

看到標題有人就要問了:你剛寫完2017怎麼跑去寫2010了?
當然是因為 2011-2016的題目我都沒做完唄
事實上每年都是A了3題,卡在第四題,而2010年的題目難度都不太高……
(我太弱了額啊)
下方正文——

T1 數字統計

原題連結
自古T1大水題,自古T4是DP。
(然而T4博弈論)
但是!這並不能阻擋 T1 簡單的事實
T1 的演算法非常簡單,列舉直接上即可,也沒什麼需要注意的點
列舉 L 到 R 之間的每個數,將每個數的每一位拆開來再判斷即可
那麼怎麼拆開呢?這對初學者來說可能是個難題(比如說當初的我)
讓我們思考一下:
一個數,如果個位為0,餘下來的數必然可以被10整除,而個位就是餘數
也就是說,我們將一個數 對 10 取餘(即 模10)

就可以取到個位
整除 10 就可以去掉個位了
於是就很容易實現了
程式碼如下:

#include<iostream>
using namespace std;
int main()
{
    int ans,i,l,r,j;
    ans=0;
    cin >> l >> r;//讀入
    for(i=l;i<=r;i++)//開始列舉
    {
        j=i;//不好直接對i下手
        while(j>0)
        {
            if(j%10==2) ans++;//如果個位是2,ans+1
            j=j/10
;//去掉個位 } } cout << ans << endl;//輸出 return 0; }

T2 接水問題

原題連結
這題我選用的是 貪心大法
(事實上這題也可以列舉每秒,那樣比較煩,也比較慢)

做法:每輸入一個時間,就把它加到 目前被佔用時間最小 的水龍頭那裡
那麼這裡就很簡單了,每次排序即可
有人會擔心時間複雜度,事實上只有 Θ(mnlogn)(快排)
當然這裡要借用一下 STL 的 sort 函式
用法就不多說了
程式碼如下:

#include<cstdio>
#include<algorithm>
using namespace std; int n,p,m,top[10005]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&p);//每次讀入一個時間 top[1]+=p;//加到佔用時間最小的水龍頭上 sort(top+1,top+m+1);//排序 } printf("%d",top[m]);//由於最後排序了一次,所以陣列尾一定是最大的數 return 0; }

T3 導彈攔截

原題連結
(事實上有兩道導彈攔截,而兩道完全不同)
這題也挺水的,用 列舉大法 即可

做法:讀入一對座標,算出它距離A裝置的距離,再從大到小排一遍序
接著我們從頭開始向後列舉分界點,分界點右邊導彈的歸A裝置,左邊的歸B裝置
我們知道如果系統去攔截導彈,那麼可以順帶把距離更短的導彈也解決了
所以我們不用擔心攔截不了什麼的
而我們在這些列舉中取最小值就可以得到答案
程式碼如下:

#include<iostream>
#include<algorithm>
using namespace std;
int n,ans1,ans2,ax,ay,bx,by,ans;
struct node
{
    int x,y,n;//xy為座標,n代表距離
}a[100005];
int RT(int a,int b,int aa,int bb)
{
    return (a-aa)*(a-aa)+(b-bb)*(b-bb);
    //計算距離,由於輸出的是平方和所以不用開根號
}
bool cmp(node x,node y)
{
    return x.n > y.n;//按距離從大到小排
}
int Max(int x,int y)
{
    return x > y ? x : y;
}
int Min(int x,int y)
{
    return x < y ? x : y;//手打速度較快
}
int main()
{
    cin >> ax >> ay >> bx >> by >> n;
    for(int i=1;i<=n;i++)
    {
        cin >> a[i].x >> a[i].y;
        a[i].n=RT(a[i].x,a[i].y,ax,ay);//計算距離
    }
    sort(a+1,a+n+1,cmp);//排序
    ans1=a[1].n;
    ans=a[1].n;//初值記得設定,可能有特例
    ans2=-2147400000;
    for(int i=2;i<=n+1;i++)
    {
        ans1=a[i].n;//上方已經說明過的過程,右邊歸A系統
        int cnt=RT(a[i-1].x,a[i-1].y,bx,by);
        ans2=Max(ans2,cnt);//左邊歸B系統
        ans=Min(ans,ans1+ans2);//存值
    }
    cout << ans << endl;//輸出
    return 0;
}

T4 三國遊戲

原題連結

博弈論傷不起啊!
——Venus

是的……作為一個蒟蒻……博弈論是我心中永遠的痛……
實在太難理解了啊喂!(╯‵□′)╯︵┻━┻
不過我還是做出來了……
這道題目的決策(我都不知道是不是這麼說)是這樣的:
由於AI每次取走的是與我們手上組成的組合默契值最高的,那麼我們每次取第二高的,好的就被我們選走了,AI很被動,而他的最好的已經被我們取走了,所以AI就只能取第二強的了,這樣就相當於 “他強任他強,我選託比昂”
舉個栗子:

編號 1 2 3 4
1 55 13 46
2 55 44 52
3 13 44 32
4 46 52 32

我們先取2,AI取走1,我們趁機取4,AI就只能取3
這樣我們的默契值就是52,AI就只有13
程式碼如下:

#include<iostream>
#include<algorithm>
using namespace std;
int n,a[505][505],ans;
bool cmp(int x,int y)
{
    return x > y;
}
int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            cin >> a[i][j];//讀入
            a[j][i]=a[i][j];//構建圖表
        }
    }
    for(int i=1;i<=n;i++)
    {
        sort(a[i]+1,a[i]+n+1,cmp);//排序,從大到小排
        ans=max(ans,a[i][2]);//每次取第二大的即可
    }
    cout << "1" << endl << ans << endl;//由於我們必勝,所以輸出1就可以了
    return 0;
}

小結

2010年的題目算是較為簡單的,就是第四題對於思考的難度比較大,還是需要動腦子的!

原創 By Venus
寫的不好大佬輕噴