10月集訓test11

又是周復一週的考試時間啦~
然而因爲粗心大意而丟分真是。。讓人很不爽。。。
0+0+15;
第一題沒有特判a=0的情況並且數組開小了,直接炸掉;
第二題。。。早知道就不寫正解了,好歹可以混上十分;
第三題,唯一一道亂搞題,連題目都沒有讀完,竟然水過了三個點。。
例行感謝WKL凱爺的良苦用心~
上題。

1.Fibonacci

題目描述

豆豆最近迷上了 Fibonacci 數,然後他開始研究 Fibonacci 數的乘積。現在他想問你某個數能不能分解成兩個 Fibonacci 數的乘積?

Fibonacci 數的定義:F0=0,F1=1,Fk=Fk-1+Fk-2 。

輸入格式

第一行一個整數 T 代表提問次數。
接下來 T 行,每行一個數字 A 表示豆豆詢問你的數。

輸出格式

對於每次提問,如果這個數可以被分解成兩個 Fibonacci 數的成績輸出“Yes”,否則輸出“No”。

樣例數據

輸入
5
5
4
12
11
10

輸出
Yes
Yes
No
No
Yes

備註

【數據範圍】
對於 50% 的數據:A≤50;
對於 100% 的數據:T≤100;0≤A≤10^9 。

首先預處理一下f數組,找出10^9以內的所有斐波那契數。
然後枚舉就可以了,大概數組開到50就可以保證通過,同時一定一定要記住判a=0的情況。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int t,a,tot,ff;
int f[55],b[55];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

int main()
{
    //freopen("fib.in","r",stdin);
    //freopen("fib.out","w",stdout);
    memset(f,0,sizeof(f));

    t=read();
    f[0]=0,f[1]=1;
    for(int i=2;i<=50;i++)
        f[i]=f[i-1]+f[i-2];
    while(t--)
    {
        ff=0;tot=0;
        a=read();
        if(a==0)
        {
            cout<<"Yes"<<endl;
            continue;
        }
        for(int i=1;i<=50;i++)
            if(a%f[i]==0)
                b[++tot]=f[i];
            else if(a<f[i])       //其實直接枚舉就可以了,這樣降低了一部分時間複雜度。
                break;
        for(int i=1;i<=tot;i++)
        {
            if(ff==1)
                break;
            int aa=a/b[i];
            for(int j=1;j<=tot;j++)
                if(aa==b[j])
                {
                    ff=1;
                    break;
                }   
                else if(aa<b[j])
                    break;
        }   
        if(ff==1)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

2.一樣遠

題目描述

企鵝國的城市結構是一棵樹,有 N 座城市和 N-1 條無向道路,每條道路都一樣長。豆豆和豆沙準備去參加 NOIP(National Olympiad in Informatics for Penguin),但是他們住在不同的地方,豆豆住在城市 A ,豆沙住在城市 B 。他們想找一個距離 A 和 B 一樣遠的集合地點,所以他們想知道有多少個城市滿足這個要求?
由於他們會參加很多次 NOIP ,所以有很多個詢問。

輸入格式

第一行一個整數 N,代表城市個數。
接下來 N-1 行,每行兩個數字 F 和 T ,表示城市 F 和城市 T 之間有一條道路。
接下來一行一個整數 M 代表詢問次數。
接下來 M 行,每行兩個數字 A 和 B ,表示這次詢問的城市 A 和城市 B(A可能與B相同)。

輸出格式

輸出 M 行,每行一個整數表示到 A 和 B 一樣遠的城市個數。

樣例數據 1

輸入
4
1 2
2 3
2 4
2
1 2
1 3

輸出
0
2

樣例數據 2

輸入
4
1 2
2 3
2 4
2
1 1
3 3

輸出
4
4

備註

【數據範圍】
對於 30% 的數據:N,M≤1000;
對於另外 10% 的數據:A=B;
對於另外 30% 的數據:保證樹的形態隨機;
對於 100% 的數據:1≤N,M≤100000。

這道題用LCA來做。
如果A和B的深度相同,就找到二者的最近公共祖先,LCA以及之上的所有點都符合題意;
如果A和B的深度不同,找到二者的中點,中點以及其子樹都符合題意。
至於求中點,先用LCA求出A和B之間的距離,然後倍增求出中點。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int to,next;
}bian[200010];
int n,x,y,z,tot,m,ans,len,e,f;
int first[200010],size[100010],dep[100010],fa[100010][25];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

inline void add(int x,int y)
{
    tot++;
    bian[tot].to=y;
    bian[tot].next=first[x];
    first[x]=tot;
}

inline void dfs(int u,int f)
{
    fa[u][0]=f;
    for(int i=1;i<=20;i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int e=first[u];e;e=bian[e].next)
    {
        int v=bian[e].to;
        if(v!=f)
        {
            dep[v]=dep[u]+1;
            dfs(v,u);
            size[u]+=size[v];
        }
    }
}

inline int lca(int x,int y)
{
    if(dep[x]<dep[y])
        swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=20;i>=0;i--)
        if(d&(1<<i))
            x=fa[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];    
}

int main()
{
    //freopen("equal.in","r",stdin);
    //freopen("equal.out","w",stdout);

    n=read();
    for(int i=1;i<n;i++)
    {
        x=read(),y=read();
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++)
        size[i]=1;
    dep[1]=0;
    dfs(1,0);
    m=read();
    while(m--)
    {
        x=read(),y=read();
        if(x==y)
        {
            printf("%d\n",n);
            continue;
        }
        z=lca(x,y);
        len=dep[x]+dep[y]-2*dep[z];     //求距離。
        if(len%2==1)
        {
            printf("0\n");
            continue;
        }
        if(dep[x]<dep[y])
            swap(x,y);
        int d=len/2;
        if(dep[x]==dep[y])        //若深度相同。
        {
            e=x,f=y;
            for(int i=20;i>=0;i--)
                if((d-1)&(1<<i))
                    e=fa[e][i];
            for(int i=20;i>=0;i--)
                if((d-1)&(1<<i))      //這兩段代碼和LCA一樣。
                    f=fa[f][i];
            ans=n-size[e]-size[f];
        }
        else                         //若不同。
        {
            e=x,f=x;
            for(int i=20;i>=0;i--)
                if(d&(1<<i))
                    e=fa[e][i];
            for(int i=20;i>=0;i--)
                if((d-1)&(1<<i))
                    f=fa[f][i];
            ans=size[e]-size[f];
        }
        cout<<ans<<endl;
    }
    return 0;
}

3.拆網線

題目描述

企鵝國的網吧們之間由網線互相連接,形成一棵樹的結構。現在由於冬天到了,供暖部門缺少燃料,於是他們決定去拆一些網線來做燃料。但是現在有 K 只企鵝要上網和別人聯機遊戲,所以他們需要把這 K 只企鵝安排到不同的機房(兩隻企鵝在同一個機房會吵架),然後拆掉一些網線,但是需要保證每隻企鵝至少還能通過留下來的網線和至少另一隻企鵝聯機遊戲。
所以他們想知道,最少需要保留多少根網線?

輸入格式

第一行一個整數 T ,表示數據組數;
每組數據第一行兩個整數 N,K ,表示總共的機房數目和企鵝數目。
第二行 N-1 個整數,第 i 個整數 Ai 表示機房 i+1 和機房 Ai 有一根網線連接(1≤Ai≤i)。

輸出格式

每組數據輸出一個整數表示最少保留的網線數目。

樣例數據

輸入
2
4 4
1 2 3
4 3
1 1 1

輸出
2
2

備註

【數據範圍】
對於 30% 的數據:N≤15;
對於 50% 的數據:N≤300;
對於 70% 的數據:N≤2000;
對於 100% 的數據:2≤K≤N≤100000,T≤10。

這道題其實比第二題要簡單一些。
分析題意可以得知,要想最後剩下的網線最少,那麼企鵝應儘可能的兩兩配對,這樣兩隻企鵝只用一根網線。
首先將邊存入,然後計算出兩兩配對的點數。若點數加到k還未加完,則退出循環直接輸出 此時的點數/2。若未加到k就加完了所有兩兩配對的點,則餘下的k-cnt個點要想加進去必須一個點帶一條邊,則ans+=k-cnt。
計算點數的時候用深度優先搜索(DFS),從最下面開始枚舉,若當前邊的兩個端點都沒有被配對過,則cnt+=2,ans++,表示增加了一對兩兩配對的點。然後對這兩個點進行標記表示已經配對。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int t,n,k,x,cnt,ans,tot;
int next[200010],to[200010],first[100010];
bool flag[100010];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

inline void add(int x,int y)
{
    tot++;
    next[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
}

inline void zql(int u,int fa)
{
    for(int i=first[u];i;i=next[i])
    {
        int v=to[i];
        if(v!=fa)
        {
            zql(v,u);
            if(!flag[v]&&!flag[u])
            {
                if(cnt<k)
                    ans++;
                cnt+=2;
                flag[v]=true;
                flag[u]=true;
            }
        }
    }
} 

int main()
{
    //freopen("tree.in","r",stdin);
    //freopen("tree.out","w",stdout);

    t=read();
    while(t--)
    {
        memset(first,0,sizeof(first));
        memset(flag,0,sizeof(flag));

        tot=0,cnt=0,ans=0;
        n=read(),k=read();
        for(int i=1;i<n;i++)
        {
            x=read();
            add(x,i+1);
            add(i+1,x);
        }
        zql(1,0);
        if(cnt<k)
            ans+=k-cnt;     //除去兩兩配對的點對,剩下的每加一個點都要加一條邊。 
        cout<<ans<<endl;    
    }
    return 0;
}

明天又要考試。。。心累。。。。伐開心
來自2017.10.23.

——我認爲return 0,是一個時代的終結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章