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,不要浪费时间,保持紧张的状态。。。↖(^ω^)↗

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