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
",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_pair
typedef 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!
");
                else
                    printf("Boys win!
");
            }
            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
",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
",a[0]-x,x,sum);
            }
            printf("%lld
",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_pair
typedef 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 == 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 = 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
",mp[1].c);
                    continue;
                }
                if(x >= san[cnt]) {
                    printf("%d
",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
",mp[pos1].c);
                } else if(abs(san[pos1]-x) > abs(san[pos2] - x))
                    printf("%d
",mp[pos2].c);
                  else printf("%d
",max(mp[pos1].c,mp[pos2].c));
            }
            printf("
");
        }
        return 0;
}
1008

1009:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-14
const 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
",(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
",ans);
        }
    }
    return 0;
}
1009
原文地址:https://www.cnblogs.com/zxhl/p/6033641.html