20171105考試總結

T1:質數

題目描述:小 X 是一位熱愛數學的男孩子,在茫茫的數字中,他對質數更有一種獨特的情感。小 X 認爲,質數是一切自然數起源的地方。在小 X 的認知裏,質數是除了本身和 1 以外,沒有其他因數的數字。但由於小 X 對質數的熱愛超乎尋常,所以小 X 同樣喜歡那些雖然不是質數,但卻是由兩個質數相乘得來的數。於是,我們定義,一個數是小 X 喜歡的數,當且僅當其是一個質數,或是兩個質數的乘積。而現在,小 X 想要知道,在 L 到 R 之間,有多少數是他喜歡的數呢?L,R<10^7;Q<10^5

成績:AC

題解:線性篩素數,在篩素數的同時用類似的方法篩出小X喜歡的數。

分析:只需一眼的大水題,非常正常的第一題。(。•́︿•̀。)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max=10000000;
const int N=3000000+10;
inline void getint(int&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
int T,tot,cnt,l,r,prime[N],like[N];
bool vis[Max],flag[Max];
inline void init(){
    for(int i=2;i<=Max;i++){
        if(!vis[i]) prime[++tot]=i;
        if(!flag[i]) like[++cnt]=i;
        for(int j=1;j<=tot&&1ll*i*prime[j]<=Max;j++){
            vis[i*prime[j]]=1;
            if(vis[i]) flag[i*prime[j]]=1;
            if(i%prime[j]==0) break ;
        }
    }
}
int main(){
    freopen("prime.in","r",stdin);
    freopen("prime.out","w",stdout);
    init(),getint(T);
    while(T--){
        getint(l),getint(r);
        l=lower_bound(like+1,like+cnt+1,l)-like;
        r=upper_bound(like+1,like+cnt+1,r)-like;
        printf("%d\n",r-l);
    }
}

T2:密室

題目描述:小 X 正困在一個密室裏,他希望儘快逃出密室。密室中有 N 個房間,初始時,小 X 在 1 號房間,而出口在 N 號房間。密室的每一個房間中可能有着一些鑰匙和一些傳送門,一個傳送門會單向地創造一條從房間 X 到房間 Y 的通道。另外,想要通過某個傳送門,就必須具備一些種類的鑰匙(每種鑰匙都要有才能通過)。幸運的是,鑰匙在打開傳送門的封印後,並不會消失。然而,通過密室的傳送門需要耗費大量的時間,因此,小 X 希望通過儘可能少的傳送門到達出口,你能告訴小 X 這個數值嗎?另外,小 X 有可能不能逃出這個密室,如果是這樣,請輸出 “No Solution”。N<=5000,M<=6000,K<=10

成績:85

題解:把每個房間根據所有鑰匙的可能拆點,連邊然後spfa。

分析:每個節點輸入時用了位運算處理可以得到的鑰匙,然而key變量沒有清0,(這樣居然能水過去85分(。﹏。*)),很快寫出這道題後,大樣例一過,就有點太過自信了 (๑>m<๑) ,寫第二題時一直在但心時間的問題,造了極限數據卡時間,反而忽略了代碼正確性的檢查。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<ctime>
using namespace std;
const int L=5000+10;
const int N=6000000+10;
const int M=20000000+10;
const int inf=0x3f3f3f3f;
inline void getint(int&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
int n,m,K,u,v,cnt,c,key,ed;
int id[L][1030],dis[N];
int fir[N],tar[M],nxt[M],w[M];
bool in[N];
inline void link(int a,int b,int c){
    tar[++cnt]=b,w[cnt]=c;
    nxt[cnt]=fir[a],fir[a]=cnt;
}
inline int spfa(){
    queue<int> q;
    memset(in,0,sizeof in);
    memset(dis,0x3f,sizeof dis);
    dis[id[1][0]]=0,q.push(id[1][0]);
    while(!q.empty()){
        int t=q.front();
        in[t]=0,q.pop();
        for(int i=fir[t];i;i=nxt[i])
            if(dis[tar[i]]>dis[t]+w[i]){
                dis[tar[i]]=dis[t]+w[i];
                if(!in[tar[i]])
                    in[tar[i]]=1,q.push(tar[i]);
            }
    }
    int tmp=inf;
    for(int i=0;i<=ed;i++)
        tmp=min(tmp,dis[id[n][i]]);
    if(tmp==inf) tmp=-1;
    return tmp;
}
int main(){
    freopen("room.in","r",stdin);
    freopen("room.out","w",stdout);
    getint(n),getint(m),getint(K);
    ed=(1<<K)-1;int tot=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=ed;j++)
            id[i][j]=++tot;
    for(int i=1;i<=n;i++){
        key=0;
        for(int j=0;j<K;j++){
            getint(c);if(c)key|=(1<<j);
        }
        for(int j=0;j<=ed;j++)
            link(id[i][j],id[i][j|key],0);
    }
    for(int i=1;i<=m;i++){
        getint(u),getint(v),key=0;
        for(int j=0;j<K;j++){
            getint(c);if(c)key|=(1<<j);
        }
        for(int j=0;j<=ed;j++)
            link(id[u][j|key],id[v][j|key],1);
    }
    int ans=spfa();
    if(~ans) printf("%d\n",ans);
    else printf("No Solution\n");
}

T3:士兵訓練

題目描述:在C國中有n位士兵,除士兵1外,每位士兵i均有且僅有一位士兵j作爲他的直屬教官。士兵i被他的直屬教官j以及所有能管轄j的士兵所管轄。每位士兵也看做能管轄自己。每位士兵均有兩個屬性值:戰鬥力bi與領導力 li。現在C國要舉行q次閱兵,每次閱兵會指定一位士兵s做總指揮,士兵s需要訓練自己所管轄的所有士兵,並以最好的精神面貌迎接閱兵式。士兵s每次閱兵訓練時有一次機會(只能使用一次或不使用),可以邀請一位不受他管轄的士兵i來指導一位他所管轄的士兵j,並會使得士兵j的戰鬥力由bj提升爲bj+li,這次提升僅對當次閱兵有效。士兵s訓練出的士兵隊伍所能展現出的精神力P爲:max(bi%bj)士兵bi被bj所管轄現在C國主席想知道,每次閱兵的隊伍所能展現出的精神力P最大能是多少?請你幫助他。

成績:30

題解:很明顯可以看出來,在不請求不能管轄士兵幫助時,答案爲子樹中第二大的值。但現在處理可以加L的情況,判斷如何使第二大的值儘量大,分幾種情形:(。。。)打if串太痛苦了,求出子樹中前三大的b,以及非子樹中前三大的l(不能重複),3^2枚舉即可。關於如何維護前三大,利用dfs序,子樹的編號自然是連續的然用線段樹維護。

分析:思路其實很好想,然而維護時,我忘了dfs序這種神奇的東西,然後一直在調莫名其妙的樹dp(其實也有人用樹dp寫出來了,然而我一蒟蒻。。°(°ˊДˋ°) °)最後慶幸我10分鐘的暴力沒出什麼問題。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define b first
#define l second
#define mp make_pair
#define pb push_back
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=300000+10;
inline void getint(int&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
int n,T,now,S,fa[N],r[N],dfn[N];
int cnt,fir[N],tar[N],nxt[N],id[N];
ll B1[N<<2],B2[N<<2],B3[N<<2],B[5];
ll L1[N<<2],L2[N<<2],L3[N<<2],L[5];
pii sol[N];
inline void link(int a,int b){
    tar[++cnt]=b;
    nxt[cnt]=fir[a],fir[a]=cnt;
}
void dfs(int x){
    dfn[x]=++now,id[now]=x;
    for(int i=fir[x];i;i=nxt[i]) dfs(tar[i]);
    r[x]=now;
}
inline void update(int x){
    ll tmp[10];
    tmp[1]=B1[lson],tmp[2]=B1[rson];
    tmp[3]=B2[lson],tmp[4]=B2[rson];
    tmp[5]=B3[lson],tmp[6]=B3[rson];
    sort(tmp+1,tmp+7);
    B1[x]=tmp[6],B2[x]=tmp[5],B3[x]=tmp[4];

    tmp[1]=L1[lson],tmp[2]=L1[rson];
    tmp[3]=L2[lson],tmp[4]=L2[rson];
    tmp[5]=L3[lson],tmp[6]=L3[rson];
    sort(tmp+1,tmp+7);
    int siz=unique(tmp+1,tmp+7)-tmp-1;
    if(siz>0) L1[x]=tmp[siz];
    if(siz>1) L2[x]=tmp[siz-1];
    if(siz>2) L3[x]=tmp[siz-2];
}
inline void build(int x,int l,int r){
    if(l==r){
        B1[x]=sol[id[l]].b;
        L1[x]=sol[id[l]].l;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    update(x);
}
void getmax_b(int x,int l,int r,int ql,int qr){
    if(l>qr||r<ql) return ;
    else if(l>=ql&&r<=qr){
        ll tmp[10];
        tmp[1]=B1[x],tmp[2]=B2[x],tmp[3]=B3[x];
        tmp[4]=B[1],tmp[5]=B[2],tmp[6]=B[3];
        sort(tmp+1,tmp+7);
        B[1]=tmp[6],B[2]=tmp[5],B[3]=tmp[4];
    }
    else{
        int mid=(l+r)>>1;
        getmax_b(lson,l,mid,ql,qr);
        getmax_b(rson,mid+1,r,ql,qr);
    }
}
void getmax_l(int x,int l,int r,int ql,int qr){
    if(l>qr||r<ql) return ;
    else if(l>=ql&&r<=qr){
        ll tmp[10];
        tmp[1]=L1[x],tmp[2]=L2[x],tmp[3]=L3[x];
        tmp[4]=L[1],tmp[5]=L[2],tmp[6]=L[3];
        sort(tmp+1,tmp+7);
        int siz=unique(tmp+1,tmp+7)-tmp-1;
        if(siz>0) L[1]=tmp[siz];
        if(siz>1) L[2]=tmp[siz-1];
        if(siz>2) L[3]=tmp[siz-2];
    }
    else{
        int mid=(l+r)>>1;
        getmax_l(lson,l,mid,ql,qr);
        getmax_l(rson,mid+1,r,ql,qr);
    }
}
int main(){
    freopen("soldier.in","r",stdin);
    freopen("soldier.out","w",stdout);
    getint(n),getint(T);
    for(int i=2;i<=n;i++)
        getint(fa[i]),link(fa[i],i);
    for(int i=1;i<=n;i++)
        getint(sol[i].b),getint(sol[i].l);
    dfs(1);
    build(1,1,n);
    while(T--){
        getint(S);
        B[1]=B[2]=B[3]=0;
        L[1]=L[2]=L[3]=0;
        getmax_b(1,1,n,dfn[S],r[S]);
        getmax_l(1,1,n,1,dfn[S]-1);
        getmax_l(1,1,n,r[S]+1,n);
        ll ans=0;
        for(int i=1;i<=3;i++)if(B[i])
            for(int j=0;j<=3;j++){
                B[i]+=L[j];
                for(int p=1;p<=3;p++)if(B[p])
                    for(int q=1;q<=3;q++)if(B[q])
                        ans=max(ans,B[p]%B[q]);
                B[i]-=L[j];
            }
        cout<<ans<<endl;
    }
    return 0;
}

總結:這場考試失誤還是比較多的,雖然都不是很大的失誤但積累起來分數就比較低了,第三題還確實有沒想到的地方,思路比正解麻煩了一點,但第二題就非常遺憾了,連續了三場考試都有較大的失誤,,,感覺好尬。。(๑Ő Ő๑),有一種不夠緊張和專注,簡單題出毒,難題有想不出來的尷尬,做第三題時擔心前面是否有錯,檢查一二題時有擔心第三題來不及,,,感覺時間永遠不夠,,尷尬尷尬尷尬尷尬o( M _ PI )o下一場注意注意力還需要更集中,,不要莫名中二發作。。o( =•ω•= )m,不要浪費時間,保持緊張的狀態。。。↖(^ω^)↗

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