2019.8.23 TEST

T1 nim

第一道题就是博弈论,考试的时候愣是没有找到规律,其实是SG函数最简单的应用,如果A[i]为奇数,SG(A[i])=A[i]+1,否则SG(A[i])=A[i]-1。最后将所有SG函数异或即可,博弈论的基本结论:所有情况异或和为0,则先手必败,反之先手必胜,代码极短:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int T,n;
long long sum;
int a[maxn];
int main(){
    scanf("%d",&T);
    while(T--){
        sum=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]%2==0) a[i]--;
            else a[i]++;
            sum^=a[i];
        } 
        if(sum==0) printf("B\n");
        else printf("A\n");
     }
    return 0;
}
View Code

T2 party

一道图论题,思维和方法都比较简单,算是今天最简单的一道题。但考试的时候忘了tarjan怎么打,还是爆零了。首先将所有点的度数统计一遍,如果度数小于题目中规定的d值,就不能要,所以要把这些点删去。现将原图中度数小于d的点存入队列之中,然后用类似拓扑排序的方法删点,打上删除标记,并且将出边所对应的点的度数减一,在删点的过程中,有可能又会遇到新的点,他的度数小于d,所以当遇到这些点的时候还是要将他们放入队列中,继续搜索直到原图满足我们的要求。接下来就用tarjan遍历图上所有的连通块,找最大解。但注意在回溯的时候还是要保存每一个连通块的最小值,如果大小相同,那么就要优先选择最小值较小的那个连通块。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
const int inf=0x7fffffff;
int n,m,d,x,y;
int deg[maxn];
struct node{
    int nxt,to;
}edge[maxn*3];
int head[maxn],cnt;
void add(int x,int y){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
bool del[maxn]; 
queue<int> q;
void topo(){//枚举删边 
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            deg[v]--;
            if(deg[v]<d&&!del[v]) q.push(v),del[v]=true; //有新的不满足要求的点还是要删去 
        }
    }
}
stack<int> sta;
bool vis[maxn],ins[maxn];
int dfn[maxn],low[maxn],in;
int tot,ljb;//tot连通块的编号 
int size[maxn];//每个联通块的大小 
int ans[maxn];//那些元素属于这个连通块 
int mi[maxn]; //连通块的最小值 
int minn;
int maxx,maxtot;
int tong[maxn];
void paint(){
    int v=sta.top();
    sta.pop();
    size[tot]++;
    ins[v]=false;
    ans[v]=tot;
    if(v<mi[tot]) mi[tot]=v;
}
void tarjan(int x){//tarjan遍历连通块 
    dfn[x]=low[x]=++in;    
    vis[x]=true;
    sta.push(x);
    ins[x]=true;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(del[v]) continue;
        if(!vis[v]){
            tarjan(v);
            low[v]=min(low[x],dfn[v]);
        }
        else if(ins[v]){
            low[x]=min(dfn[v],low[x]);
        }
    }
    if(dfn[x]==low[x]){//找到了一个 
        tot++;
        while(sta.top()!=x){
            paint();
        } 
        paint();
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&d);
    for(register int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
        deg[x]++;deg[y]++;
    }
    for(int i=1;i<=n;i++){
        if(deg[i]<d) q.push(i),del[i]=true;
    }
    topo();
    for(int i=1;i<=n;i++){
        if(!dfn[i]&&!del[i]) tarjan(i);
    }
    for(int i=1;i<=tot;i++){
        if(size[i]>size[maxtot]) minn=mi[i],maxtot=i;
        else if(size[i]==size[maxtot]&&minn>mi[i]) minn=mi[i],maxtot=i;//还需要注意特判 
     }
     printf("%d\n",size[maxtot]);
    for(int i=1;i<=n;i++){
        if(ans[i]==maxtot) tong[++ljb]=i; 
    }
    sort(tong+1,tong+1+ljb);
    for(int i=1;i<=ljb;i++) printf("%d ",tong[i]);
    printf("\n");
    return 0;
}
View Code

T3 history

其实想到思路还是比较简单的,这道题方法还是比较多的,但是我还是只能稍微理解在线的按秩合并的并查集做法。而且这道题的取模也是神仙,不能按他题上的搞。

并查集不能用路径压缩,他的父亲的时间戳一定是比他晚的,因为连边时的时间戳是保存在秩较小的点上的。最后就按照题上的判断就完了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;;
int n,m;
char opt[666];
int fa[maxn];
int size[maxn];
int year[maxn];
int cnt;
bool angry; 
int x,y,c,t;
int get(int x,int tt){
    while(x!=fa[x]&&year[x]<=tt) x=fa[x];
    return x;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) fa[i]=i,size[i]=1;
    for(int i=1;i<=m;i++){
        scanf("%s",opt);
        if(opt[0]=='K') scanf("%d",&c),angry=false;
        if(opt[0]=='R'){
            scanf("%d%d",&x,&y);
            if(angry){
                if((x+=c)>=n) x-=n;
                if((y+=c)>=n) y-=n; 
            }
            cnt++;
            int f1=get(x,cnt);
            int f2=get(y,cnt);
            if(f1==f2) continue;
            if(size[f1]<size[f2]){
                fa[f1]=f2;
                size[f2]+=size[f1];
                   year[f1]=cnt;//father的时间戳更晚,路径的时间戳保存在秩较小的节点上 
            }
            else{
                fa[f2]=f1;
                size[f1]+=size[f2];
                year[f2]=cnt;
            }
        }
        if(opt[0]=='T'){
            scanf("%d%d%d",&x,&y,&t);
            angry=((get(x,cnt-t)==get(y,cnt-t))||(get(x,cnt)!=get(y,cnt)));//不符合题中要求 
            if(angry) printf("N\n");
            else printf("Y\n");
        }
    }
    return 0;
} 
View Code

猜你喜欢

转载自www.cnblogs.com/LJB666/p/11402123.html