[Contests]2016 ACM/ICPC Asia Regional Dalian Online(1006/7/8/9)

来源:互联网 发布:淘宝助理6.0 官方 编辑:程序博客网 时间:2024/06/08 09:56

1006 Football Games

题意:

每组球队中有若干个队伍,每两个队伍之间比赛,胜得2分,负得0分,平局得1分;

然后判断题目给出的每组队伍得分是否合理,若合理输出“T”,否则输出“F”

思路:

据聚聚说是Landau's Theorem(兰道定理),弱渣表示数学定理什么的无能为力……

是这样的,我们判断得分是否合理,那么也就是说得分不能超过合理分数;

一共n个球队得分,先进行排序,可以发现如下规律(兰道定理)

1、总分一定等于n(n-1),
2、第i个分数>=i(i-1)

注意所有球队的总分加一起可能很大,用__int64
注意这句话 "Multiple test cases, process till end of the input." 看仔细怎么输入
还有时间超限很多次,为啥呢,因为arr数组开太小,一定仔细看N的范围是啥呀……

代码:

#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;//const int N = 100+5;const int N = 20000+10;__int64 arr[N];int main(){    int t, m;    //scanf("%d", &t);    //while(t-->0){    while(~scanf("%d", &t))    while(t-->0){        int ans=0, flag=1;        scanf("%d", &m);        for(int i=0; i<m; i++){            scanf("%I64d", &arr[i]);            ans += arr[i];        }        if(ans!=m*(m-1) || m<=1){            printf("F\n");            continue;        }        ans = 0;        sort(arr, arr+m);        for(int i=0; i<m; i++){            ans += arr[i];            if(ans < i*(i+1)){                flag = 0;                break;            }        }        /*        if(flag) {printf("T\n"); continue;}        printf("F\n");        */        printf(flag?"T\n":"F\n");    }    return 0;}


1007 Friends and Enemies

题意:

n个人m种颜色,每两个人之间必然存在朋友或敌人任一关系。如果两人是朋友,那么这两人的项链中至少有一块石头颜色相同;如果两人是敌人,那么这两人的项链中没有相同颜色的石头,我们要求的是n个人中每两人任意关系,如果项链需要的颜色都<=m, 输出“T”,否则输出“F”,注意项链可以为空

思路:

n个点的图,要求有尽量多的边,并且不存在三元环,这个边数就是m的下界
对于一个n个结点的没有三元环的图,边数最大的就是完全二分图
于是答案就是(n/2 * ((n+1)/2))

代码:

#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;int main(){    int n, m;    while(~scanf("%d%d", &n, &m)){        //注意运算的优先顺序        if((n/2) * ((n+1)/2) <= m){            printf("T\n");            continue;        }        printf("F\n");    }    return 0;}


1008 Function

题意:

给你一串数字,然后进行查询操作,输入l和r,代表查询区间[l,r],求F(l,r), f[l,r]的函数表达式如下

F(l,r)={AlF(l,r1) modArl=r;l<r.

思路:

用线段树维护区间最小值
遇到比arr[l]大的掠过,<=其的就取余%

最重要的是查询过程,返回的是>=arr[l]的最小下标

总之,如果能进子树(说明有比val小的值存在),左子树找的到就return 下标

左子树找不到(说明最小值所在下标不在范围内),再进右子树,右子树找的到就return 下标
如果右子树中最小值所在下标不在范围内,那么结束了,return -1
其实就是如果你找一个区间最小值,这个最小值不在你问询的范围内,那么结束return -1; 如果能找到就返回下标

代码:

#include <stdio.h>#include <string.h>#include <iostream>#include<vector>#define inf 0x7f7f7f7f#define lson root<<1,left,mid#define rson root<<1|1,mid+1,rightusing namespace std;/*线段树维护区间最小值遇到比之小的掠过,>=其的就取余%*/const int N = 1e5+5;int arr[N];struct{    int val;    int l;    int r;}Tree[N*4];int my_min(int x, int y){    return x<y?x:y;}int pushup(int root){    return my_min(Tree[root<<1].val, Tree[root<<1|1].val);}void build(int root, int left, int right){    Tree[root].l = left;    Tree[root].r = right;    if(left == right){        Tree[root].val = arr[left];        return;    }    int mid = (left+right) >> 1;    build(lson);    build(rson);    Tree[root].val = pushup(root);}//返回的是>=arr[l]的最小下标/*int query(int root, int ql, int qr, int val){//查询[ql,qr]    if(ql>Tree[root].r || qr<Tree[root].l)//说明[ql,qr]不会涉及此root        return ql+1;//0<=a[i]<=1e5    if(ql<=Tree[root].l && qr>=Tree[root].r){        if(Tree[root].val < val) return Tree[root].r;    }    if(Tree[root<<1].val < val)        return query(root<<1, ql, qr, val);    else        return query(root<<1|1, ql, qr, val);}*/int query(int root, int ql, int qr, int val){    if(Tree[root].l == Tree[root].r){        if(Tree[root].val <= val) return Tree[root].r;        return -1;    }    //如果root左子树可进,那么进    if(ql<=Tree[root<<1].r && val>=Tree[root].val){        //如果root左子树可以找到,那么return        int tmp = query(root<<1, ql, qr, val);        if(tmp != -1) return tmp;        //如果root左子树不能找到,那么肯定在root右子树,还是进右子树        if(qr>=Tree[root<<1|1].l && val>=Tree[root].val)            return query(root<<1|1, ql, qr, val);    }    //如果root右子树可进,那么进    if(qr>=Tree[root<<1|1].l && val>=Tree[root].val)        return query(root<<1|1, ql, qr, val);    return -1;}int main(){    int t, n, m;    int l, r;    scanf("%d", &t);    while(t-->0){        scanf("%d", &n);        for(int i=1; i<=n; i++)            scanf("%d", &arr[i]);        build(1,1,n);        scanf("%d", &m);        while(m-->0){            scanf("%d%d", &l, &r);            int ans = arr[l];            l++;            while(l <= r){                l = query(1,l,r,ans);                if(l == -1) break;                ans %= arr[l];            }            printf("%d\n", ans);        }    }    return 0;}/*153 4 2 9 311 4----------1*/
反思:

真的写这道题的时候仿佛一个智障……整个脑子都被搅乱了,真的是……vegetable



1009 Sparse Graph

题意:

给一个无向图和源点s,求在补图中源点s到其他点的最短距离,如果到其他点不通的话输出“-1”

思路:

补图求最短路

代码:

#include<cstdio>#include<cstring>#include<queue>#include<set>#include<algorithm>using namespace std;const int N = 200000+5;const int M = 5500+5;const int inf = 1<<29;typedef long long LL;int head[N];int dis[N];bool vis[N];struct Edge{    int v;    int c;    int next;}edge[N<<1];int p = 0;void add(int u,int v){    edge[p].v = v;    edge[p].c = inf;    edge[p].next = head[u];    head[u]  = p++;}struct node{    int v,c;    node(int _v,int _c){        v = _v;        c = _c;    }    bool operator < (const node &a) const{        return c > a.c;    }};void BFS(int n, int s){    queue<int>Q;    Q.push(s);    dis[s] = 0;    //dis[n] = inf;    //fill(dis+1, dis+n+1, inf);    set<int>sa, sb;    for(int i=1; i<=n; i++)    if(i != s)        sa.insert(i);    while(!Q.empty())    {        int Now = Q.front();        Q.pop();        for(int i=head[Now]; i!=-1; i=edge[i].next){            int New = edge[i].v;            if(!sa.count(New)) continue;            sa.erase(New);            sb.insert(New);        }        for(set<int>::iterator it=sa.begin(); it!=sa.end(); it++){            Q.push(*it);            dis[*it] = dis[Now] + 1;        }        sa.swap(sb);        sb.clear();    }}int main(){    int t, n, m, s;    int u, v;    scanf("%d", &t);    while(t-->0){        scanf("%d%d", &n, &m);        p=0;        memset(head,-1,sizeof head);        memset(vis,false,sizeof vis);        memset(dis, 0, sizeof(dis));        for(int i=0; i<m; i++){            scanf("%d%d",&u, &v);            add(u, v);            add(v, u);        }        scanf("%d", &s);        BFS(n, s);        for(int i=1; i<=n-2; i++){            if(i != s){                if(dis[i] == 0)                    dis[i] = -1;                printf("%d ", dis[i]);            }        }        if(s==n)            printf("%d\n", dis[n-1]);        else if(s==n-1){            if(dis[n] == 0)                dis[n] = -1;            printf("%d\n", dis[n]);        }        else{            if(dis[n-1] == 0)                dis[n-1] = -1;            if(dis[n] == 0)                dis[n] = -1;            printf("%d %d\n", dis[n-1], dis[n]);        }    }    return 0;}/*35 71 21 31 52 33 43 54 514 11 212 01---2 -1 1 32 1 11*/


1010 Weak Pair

思路:

是树状数组/线段树,写不出来,功力太浅,等多几个树状数组找找感觉再回来做_(:зゝ∠)_

0 0