首页 > 代码库 > 2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)(5/10)

2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)(5/10)

1001: 传递要求 a->b->c && a->c

我的做法就是利用bitset预处理出x点可达点集,与可达到x点的点集

那么如何检验这个图是否传递;枚举完b和,枚举可达b点集中的点x,那么点x可达点集要包含c点集,这个利用bieset可以快速判断

整个做法就是(n^2)

技术分享
#include<cstdio>#include<cstring>#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<bitset>#include<set>#include<queue>#include<stack>#include<map>#include<cstdlib>#include<cmath>#define PI 2*asin(1.0)#define LL long long#define pb push_back#define pa pair<int,int>#define clr(a,b) memset(a,b,sizeof(a))#define lson lr<<1,l,mid#define rson lr<<1|1,mid+1,r#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)#define key_value ch[ch[root][1]][0]const int  MOD = 1000000007;const int N = 2016+15;const int maxn = 200+ 14;const int mm=100010;const int letter = 130;const int INF = 1e9;const double pi=acos(-1.0);const double eps=1e-8;using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}    return x*f;}int T,n;char s[N][N];bitset<N>vs[2][N],tt;int main(){    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);        for(int i=1;i<=n;i++) vs[0][i].reset(),vs[1][i].reset();        for(int i=1;i<=n;i++){            for(int j=1;j<=n;j++){                if(s[i][j]==P){                    vs[1][i][j]=vs[0][j][i]=1;                }            }        }        int flag=1;        for(int x=1;x<=n;x++){            for(int i=1;i<=n;i++){                if(vs[0][x][i]){                    tt=vs[1][i]&vs[1][x];                    if(tt!=vs[1][x]){flag=0;break;}                }            }            if(!flag) break;        }        if(!flag){            puts("N");            continue;        }        for(int i=1;i<=n;i++) vs[0][i].reset(),vs[1][i].reset();        for(int i=1;i<=n;i++){            for(int j=1;j<=n;j++){                if(s[i][j]==Q){                    vs[1][i][j]=vs[0][j][i]=1;                }            }        }        flag=1;        for(int x=1;x<=n;x++){            for(int i=1;i<=n;i++){                if(vs[0][x][i]){                    tt=vs[1][i]&vs[1][x];                    if(tt!=vs[1][x]){flag=0;break;}                }            }            if(!flag) break;        }        if(flag) puts("T");        else puts("N");    }    return 0;}
1001

1003:对于给定以x为根的游戏,我们把看看作是多条链的组合游戏(组合博弈)

那么一条链怎么赢?

  我们以低位为接近根的边权:

    00001:先手必赢 ,000010:先手必败

    00011:先手必赢, 000100:先手必败………………

  找到规律接近根的地方为1,先手必赢,否则必败

  根据博弈组合游戏,那么答案就是包含x点的边权的异或和来判断先手是否能赢

技术分享
#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define ls i<<1#define rs ls | 1#define mid ((ll+rr)>>1)#define pii pair<int,int>#define MP make_pairtypedef long long ll;const long long INF = 1e18+1LL;const double Pi = acos(-1.0);const int N = 1e5+10, maxn = 1e3+20, inf = 2e9;struct edge{    int v,w;    int nex;}edge[N];int head[N];int edg;void init(){    memset(head,-1,sizeof(head));    edg=0;}void add(int u,int v,int w){    edg++;    edge[edg].v=v;    edge[edg].w=w;    edge[edg].nex=head[u];    head[u]=edg;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        init();        int n,m;        scanf("%d%d",&n,&m);        for(int i=1;i<n;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add(u,v,w);            add(v,u,w);        }        while(m--)        {            int hh;            scanf("%d",&hh);            if(hh==0)            {                int x;                scanf("%d",&x);                int ANS=0;                for(int i=head[x];i!=-1;i=edge[i].nex)                {                    int w=edge[i].w;                    ANS^=w;                }                if(ANS)                    printf("Girls win!\n");                else                    printf("Boys win!\n");            }            else            {                int u,v,w;                scanf("%d%d%d",&u,&v,&w);                for(int i=head[u];i!=-1;i=edge[i].nex)                {                    if(edge[i].v==v)                    {                        edge[i].w=w;                        break;                    }                }                for(int i=head[v];i!=-1;i=edge[i].nex)                {                    if(edge[i].v==u)                    {                        edge[i].w=w;                        break;                    }                }            }        }    }    return 0;}
1003

1005:

  假设我们确定了前两列的状态,那么整个行列就可以O(n)推出来了

  枚举状态就好了

技术分享
 #include<bits/stdc++.h>    using namespace std;    #pragma comment(linker, "/STACK:102400000,102400000")    #define ls i<<1    #define rs ls | 1    #define mid ((ll+rr)>>1)    #define pii pair<int,int>    #define MP make_pair    typedef long long LL;    const long long INF = 1e18+1LL;    const double Pi = acos(-1.0);    const int N = 1e4+10, maxn = 1e3+20, inf = 2e9;    const LL mod = 100000000+7;    int n;    char a[N];    int b[N];    LL cc(int x){        if(x==0||x==2) return 1ll;        return 2ll;    }    int main(){        int T;        scanf("%d",&T);        while(T--){            scanf("%s",a);            n=strlen(a);            for(int i=0;i<n;i++) a[i]-=0;            if(n==1){                if(a[0]==1) puts("2");                else if(a[0]==0||a[0]==2) puts("1");                else puts("0");                continue;            }            LL ans=0;            for(int x=0;x<=min(2,(int)a[0]);x++){                ///printf("x = %d\n",x);                LL sum=1;                if(a[0]-x>2||a[0]-x<0) continue;                b[0]=a[0]-x,b[1]=x;                sum=sum*cc(b[0])%mod,sum=sum*cc(b[1])%mod;                for(int i=2;i<n;i++){                    b[i]=a[i-1]-b[i-1]-b[i-2];                    if(b[i]<0||b[i]>2) {sum=0;break;}                    sum=sum*cc(b[i])%mod;                }                if(b[n-1]+b[n-2]!=a[n-1]) sum=0;                ans=(ans+sum)%mod;                ///printf("%d %d sum = %lld\n",a[0]-x,x,sum);            }            printf("%lld\n",ans);        }        return 0;    }
1005

1008:

  n只有100,预处理n^2出每段区间的异或和

  那么查询的时候就二分找最近的值

技术分享
#include<bits/stdc++.h>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")#define ls i<<1#define rs ls | 1#define mid ((ll+rr)>>1)#define pii pair<int,int>#define MP make_pairtypedef long long LL;const long long INF = 1e18+1LL;const double Pi = acos(-1.0);const int N = 1e5+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9;struct ss{    int value,c;}mp[N];bool cmp(ss s1,ss s2) {        if(s1.value =http://www.mamicode.com/= s2.value) return s1.c>s2.c;        else return s1.value < s2.value;}int n,sum[N],a[N],cnt,san[N];map<int,int > H;int main() {        int T;        scanf("%d",&T);        while(T--) {            cnt = 0;            scanf("%d",&n);            H.clear();            for(int i  =1; i<=n; ++i)                scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i];            for(int i = 1; i <= n; ++i) {                for(int j = i; j <= n; ++j) {                    if(H[sum[j]^sum[i-1]]) {                        mp[H[sum[j]^sum[i-1]]].c = max(j-i+1,mp[H[sum[j]^sum[i-1]]].c);                    } else {                        mp[++cnt].value = http://www.mamicode.com/sum[j]^sum[i-1];                        mp[cnt].c = j-i+1;                        H[sum[j]^sum[i-1]] = cnt;                    }                }            }            sort(mp+1,mp+cnt+1,cmp);            for(int i = 1; i <= cnt; ++i) {                san[i] = mp[i].value;            }            int m,x;            scanf("%d",&m);            while(m--) {                scanf("%d",&x);                if(x <= san[1]) {                    printf("%d\n",mp[1].c);                    continue;                }                if(x >= san[cnt]) {                    printf("%d\n",mp[cnt].c);                    continue;                }                int pos1 = lower_bound(san+1,san+1+cnt,x) - san;                int pos2 = pos1-1;                if(abs(san[pos1]-x) < abs(san[pos2] - x)) {                    printf("%d\n",mp[pos1].c);                } else if(abs(san[pos1]-x) > abs(san[pos2] - x))                    printf("%d\n",mp[pos2].c);                  else printf("%d\n",max(mp[pos1].c,mp[pos2].c));            }            printf("\n");        }        return 0;}
1008

1009:

技术分享
#include<bits/stdc++.h>using namespace std;#define ll long long#define pi (4*atan(1.0))#define eps 1e-14const int N=2e5+10,M=4e6+10,inf=1e9+10,mod=1e9+7;const ll INF=1e18+10;int a[110];ll check(ll x){    int sum=0;    while(x)    {        sum++;        x/=2;    }    return sum;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        ll l,r;        scanf("%lld%lld",&l,&r);        int L=check(l);        int R=check(r);        if(L!=R)        {            printf("%lld\n",(1ll<<max(L,R))-1);        }        else        {            if(L==0) {                puts("0");                continue;            }            int ps=L-1;            int cnt=0;            while((l&(1ll<<ps))==(r&(1ll<<ps))&&ps>=0){                a[++cnt]=(l&(1ll<<ps))>>ps;                ps--;            }            for(int i=cnt+1;i<=L;i++) a[i]=1;            ll ans=0;            for(int i=1;i<=L;i++) ans=ans*2ll+1ll*a[i];            printf("%lld\n",ans);        }    }    return 0;}
1009

 

2016年中国大学生程序设计竞赛(合肥)-重现赛(感谢安徽大学)(5/10)