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

6 篇文章 0 订阅
5 篇文章 0 订阅

HDU 5969最大的位或

最大的位或

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 274    Accepted Submission(s): 146


Problem Description

B君和G君聊天的时候想到了如下的问题。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。

 


Input

包含至多10001组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 1018

 


Output

对于每组数据输出一行,表示最大的位或。

 


Sample Input

 
 
5 1 10 0 1 1023 1024 233 322 1000000000000000000 1000000000000000000

 


Sample Output

 
 
15 1 2047 511 1000000000000000000

思路:给l的二进制补1,只要没超过r就一直补,最后得到的数和r或运算就是结果。

#include <bits/stdc++.h>
using namespace std;
#define ll long long int
int main()
{
    ll l,r;
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%I64d %I64d", &l, &r);
        ll tmp = 0, n = 0, s = 1, k = l;
        while((k|(tmp+(s<<n)))<=r) {
            tmp += (s<<n);
            n++;
        }
        if(tmp==0) printf("%I64d\n", r);
        else printf("%I64d\n", tmp|l|r);
    }
}


HDU 5968异或密码

异或密码

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 297    Accepted Submission(s): 113


Problem Description
晨晨在纸上写了一个长度为N的非负整数序列{ ai }。对于这个序列的一个连续子序列{ al,al+1,ar }晨晨可以求出其中所有数异或的结果 alxoral+1xor...xorar 其 中xor表示位异或运算,对应C、C++、 Java等语言中的^运算。
小璐提出了M个询问,每个询问用一个整数 xi 描述。
对于每个询问,晨晨需要找到序列{ ai }的所有连续子序列,求出每个子序列异或的结果,找到所有的结果中与 xi 之差的绝对值最小的一个,并告诉小璐相应子序列的长度。
若有多个满足条件的连续子序列,则告诉小璐这些子序列中最长的长度。
 

Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据共两行。
第一行包含N+1个非负整数。其中第一个数为N,表示序列的长度;接下来N 个数,依次描述序列{ ai }中的每个数。
第二行包含M+1个整数。其中第一个数为M,表示询问的个数;接下来M个数 xi ,每个数对应题目描述中的一个询问。
保证 1 <= N <= 100,1 <= M <= 100, ai <= 1024,| xi | <= 1024,数据组数 <= 100。
 

Output
对于每组数据输出M + 1行。前M行对应晨晨M个询问的回答,第M + 1行为空行
 

Sample Input
      
      
2 2 1 1 2 0 2 3 1 2 4 3 10 5 1
 

Sample Output
      
      
2 1 3 2 1

思路:暴力出子序列,用结构体保存它的异或和 和 长度,排序,按异或和升序排,异或和相同的按长度降序排。二分查找和x最接近的数,用这个数和它左边一个和右边一个来

更新结果,注意左边可能有多个相同的值,由于排序的原因,左边如果有多个相同的值就要取最左,右边就直接取第一个。

#include <bits/stdc++.h>
using namespace std;
#define inf 1<<30
int a[105], pre[105], ans[105];
int x, res;
struct region{
    int l, r, val;
    dis(){return r-l+1;}
}rom[10010];
bool cmp(const region a, const region b){
    if(a.val==b.val) return (a.r-a.l+1)>(b.r-b.l+1);
    return a.val<b.val;
}
int main()
{
    int N, M, i, j, T, k, p;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &N);
        scanf("%d", &a[1]);
        pre[1] = a[1];
        for(i = 2;i <= N;i++){
            scanf("%d", &a[i]);
            pre[i] = pre[i-1]^a[i];
        }
        p = 0;
        for(i = 1;i <= N;i++){
            for(j = 1;j+i-1<=N;j++){
                int sum = pre[j+i-1]^pre[j-1];
                if(j-1<1) sum = pre[j+i-1];
                if(i==1) sum = a[j];
                rom[p].l=j,rom[p].r=j+i-1,rom[p].val=sum;
                p++;
            }
        }
        memset(ans, 0, sizeof ans);
        sort(rom, rom+p, cmp);
        /*for(i = 0;i < p;i++){
            printf("%d %d %d\n", rom[i].l,rom[i].r,rom[i].val);
        }*/
        scanf("%d", &M);
        for(k = 0;k < M;k++){
            scanf("%d", &x);
            int L=0, R=p-1, mid, tp=-1;
            //printf("---\n");
            while(L<=R){
                //printf("%d %d\n", L, R);
                mid = (L+R)/2;
                if(rom[mid].val>=x){
                    R = mid-1;
                }else L = mid+1;
            }//printf("--%d %d %d\n", L, R, mid);
            tp = mid;
            res = inf;
            int tmp;
            if(tp>=1){//求左边
                tmp = rom[tp-1].val;
                while(rom[tp-1].val==tmp&&tp-1>=0)tp--;
                if(abs(rom[tp].val-x)<res){
                    res = abs(rom[tp].val-x);
                    ans[k] = rom[tp].dis();
                }else if(abs(rom[tp].val-x)==res) ans[k] = max(ans[k], rom[tp].dis());
            }
            tp = mid;
            if(tp<p-1){//求右边
                if(abs(rom[tp+1].val-x)<res){
                    res = abs(rom[tp+1].val-x);
                    ans[k] = rom[tp+1].dis();
                }else if(abs(rom[tp+1].val-x)==res) ans[k] = max(ans[k], rom[tp+1].dis());
            }
            tp = mid;
            if(abs(rom[tp].val-x)<res){
                res = abs(rom[tp].val-x);
                ans[k] = rom[tp].dis();
            }else if(abs(rom[tp].val-x)==res) ans[k] = max(ans[k], rom[tp].dis());
        }

        for(k = 0;k < M;k++) printf("%d\n", ans[k]);
        printf("\n");
    }
}


HDU5961 传递

传递

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 354    Accepted Submission(s): 160


Problem Description

我们称一个有向图G是传递的,当且仅当对任意三个不同的顶点a,,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。


现在,给你两个有向图P = (V, Ep )和Q = (V, Ee ),满足:
1.   EP Ee 没有公共边;
2.  (V, EpEe )是一个竞赛图。
你的任务是:判定是否P,Q同时为传递的。

 


Input

包含至多20组测试数据。
第一行有一个正整数,表示数据的组数。
对于每组数据,第一行有一个正整数n。接下来n行,每行为连续的n个字符,每 个字符只可能是’-’,’P’,’Q’中的一种。
如果第i行的第j个字符为’P’,表示有向图P中有一条边从i到j;
如果第i行的第j个字符为’Q’,表示有向图Q中有一条边从i到j;
否则表示两个图中均没有边从i到j。
保证1 <= n <= 2016,一个测试点中的多组数据中的n的和不超过16000。保证输入的图一定满足给出的限制条件。

 


Output

对每个数据,你需要输出一行。如果P! Q都是传递的,那么请输出’T’。否则, 请输出’N’ (均不包括引号)。

 


Sample Input

 
 
4 4 -PPP --PQ ---Q ---- 4 -P-P --PQ P--Q ---- 4 -PPP --QQ ---- --Q- 4 -PPP --PQ ---- --Q-

 


Sample Output

 
 
T N T N
Hint
在下面的示意图中,左图为图为Q。
注:在样例2中,P不是传递的。在样例4中,Q不是传递的。

思路:按照规则画画图可以知道,如果是传递图,是没有那个点的深度是大于2的,所以每个点bfs,如果出现深度大于2就结束(N),用过蛮暴力的方式:利用邻接矩阵来3个3个点地尝试——3s, bfs——485ms,好一段时间认为只要是间接连通的点,都要有一条直接的边,结果题目只要求任意3个点。

#include <bits/stdc++.h>
using namespace std;
#define maxn 2050
int n;
char s[maxn][maxn];
char rt[3] = {'P', 'Q'};
vector<int> M[2][maxn];
void add(int id, int u, int v){
    M[id][u].push_back(v);
}
struct node{
    int to, deep;
};
bool vis[2][maxn], flag;
void bfs(int id, int u){
    vis[id][u] = 1;
    node now, next;
    now.to = u, now.deep = 1;
    queue<node> q;
    q.push(now);
    while(!q.empty()){
        now = q.front();
        q.pop();
        int point = now.to;
        //printf("%d %d\n", id, point);
        for(int i = 0;i < M[id][point].size();i++){
            int son = M[id][point][i];
            if(vis[id][son]) continue;
            next.to = son, next.deep = now.deep+1;
            if(next.deep>=3){
                flag = 0;
                return;
            }
            vis[id][son] = 1;
            q.push(next);
        }
    }
}
int main()
{
    int T, i, j, k, cnt;
    scanf("%d", &T);
    while(T--){
        for(i = 0;i < maxn;i++){
            M[0][i].clear();
            M[1][i].clear();
        }
        memset(vis, 0, sizeof vis);
        scanf("%d", &n);
        for(i = 1;i <= n;i++) scanf("%s", s[i]+1);
        for(i = 1;i <= n;i++){
            for(j = 1;j <= n;j++){
                if(s[i][j]=='P'){
                    add(0, i, j);
                }
                else if(s[i][j]=='Q') {
                    add(1, i, j);
                }
            }
        }
        flag = 1;
        for(i = 1;i <= n;i++){
            if(vis[0][i]&&vis[1][i]) continue;
            if(!vis[0][i]) bfs(0, i);
            if(!flag) break;
            if(!vis[1][i]) bfs(1, i);
            if(!flag) break;
        }
        if(!flag) printf("N\n");
        else printf("T\n");
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值