AtCoder Grand Contest 002 做题记录

A - Range Product

题意:给定两个整数 a a b b ab a ≤ b ),判断 bi=ai ∏ i = a b i 的正负形。
109ab109 − 10 9 ≤ a ≤ b ≤ 10 9
解答:分类讨论即可。

#include 
using namespace std;
typedef long long LL;
inline int rd() {int r;scanf("%d",&r);return r;}
int main() {
    int a = rd(), b = rd();
    if (1LL * a * b <= 0) {
        puts("Zero");
        return 0;
    }
    if (a>0) {
        puts("Positive");
        return 0;
    }
    a = abs(a);
    if (b < 0) a -= abs(b+1);
    puts(a&1 ? "Negative" : "Positive");
    return 0;
}

B - Box and Ball

题意:一开始有 N N 个盒子,每个盒子里面有一个球。第一个盒子里的球是红球,其余的球为白球。接下来有 M M 个操作,每次从 xi x i 盒子中任意取一个球放入 yi y i 盒子中。询问所有操作结束后有多少个盒子内有可能有红球。
2N105 2 ≤ N ≤ 10 5
1M105 1 ≤ M ≤ 10 5
1xi,yiN 1 ≤ x i , y i ≤ N
解答:若一次操作可以将一个盒子的球清空,那么这个盒子就一定没有红球,否则只要有红球可能进入该盒子,那么到最后该盒子就有可能有红球。

#include 
#define N 1000500
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii;
pii t[N];
inline int rd() {int r;scanf("%d",&r);return r;}
int n,m;
int main() {
    n = rd(), m = rd();
    t[1] = pii(1,1);
    for (int i=2;i<=n;i++) t[i] = pii(0, 1);
    for (int i=1;i<=m;i++) {
        int a = rd(), b = rd();
        t[b].x |= t[a].x;
        t[b].y ++;
        t[a].y --;
        if (!t[a].y) t[a].x = 0;
    }

    int ans = 0;
    for (int i=1;i<=n;i++) if (t[i].x) ans++;
    cout << ans << endl;
    return 0;
}

C - Knot Puzzle

题意:给定 N N 条绳子,第 i i 条长度为 ai a i ,现在用 N1 N − 1 个结将所有绳子连成一条。你可以每次选取长度大于等于 L L 的绳子,将其中一个结解开。询问是否可以将所有结都解开,若可以输出”Possible”并给出方案,否则输出”Impossible”。
2N105 2 ≤ N ≤ 10 5
1L109 1 ≤ L ≤ 10 9
1ai109 1 ≤ a i ≤ 10 9
解答:如果不存在连续的两段绳子 ai a i ai+1 a i + 1 满足 ai+ai+1L a i + a i + 1 ≥ L ,则无解。(考虑解开最后一个结时候的情况)。否则以这两段绳子为中心,解开两边的结,最后再解开这个结。

#include 
#define N 1000500
using namespace std;
int n,L,a[N];
inline int rd() {int r;scanf("%d",&r);return r;}
int main() {
    n = rd(), L = rd();
    for (int i=1;i<=n;i++) a[i] = rd();

    int d = 0;
    for (int i=1;iif (a[i]+a[i+1] >= L) d = i;
    if (!d) {
        puts("Impossible");
    } else {
        puts("Possible");
        for (int i=1;iprintf("%d\n",i);
        for (int i=n-1;i>d;i--) printf("%d\n",i);
        printf("%d\n",d);
    }

    return 0;
}

D - Stamp Rally

题意:给定一张 N N 个点 M M 条边的无向图,现在有 Q Q 次游戏,每次游戏两兄弟从 xi x i yi y i 出发,两个人一共要访问过 zi z i 个点(一个人重复访问一个点,或者两个人都访问过的一个点,算作一个点)。 两个人所需要花费的代价为他们所经过的编号最大那条边的编号,要求最小化代价并输出这个代价。
3N105 3 ≤ N ≤ 10 5
N1M105 N − 1 ≤ M ≤ 10 5
1Q105 1 ≤ Q ≤ 10 5
解答:若询问只有一个,将边从小到大加入无向图,讨论一下判断连通块大小即可。多组询问用整体二分即可。

#include 
#define N 100050
using namespace std;

struct HbFS{int _,x,y,t;}Q[N],tmp[N];
int fa[20][N],siz[20][N],ans[N],T[20];
int a[N],b[N],n,m,q;

inline int rd() {int r;scanf("%d",&r);return r;}

int gf(int dep,int x) {
    return fa[dep][x] == x ? x : fa[dep][x] = gf(dep, fa[dep][x]);
}

void mer(int dep, int x, int y) {
    int p1 = gf(dep, x);
    int p2 = gf(dep, y);
    if (p1 == p2) return ;
    fa[dep][p1] = p2;
    siz[dep][p2] += siz[dep][p1];
    siz[dep][p1] = 0;
}

void solve(int ql,int qr,int vl,int vr,int dep) {
    if (vl == vr) {
        for (int i=ql;i<=qr;i++) ans[ Q[i]._ ] = vl;
        return ;
    }

    int mid = (vl + vr) >> 1;

    while (T[dep]+1 <= mid) {
        T[dep]++;
        int cur = T[dep];
        mer(dep, a[cur], b[cur]);
    }

    int dl = ql, dr = qr;
    for (int i=ql;i<=qr;i++) {
        int p1 = gf(dep, Q[i].x);
        int p2 = gf(dep, Q[i].y);
        if (p1 == p2) {
            if (siz[dep][p1] >= Q[i].t) 
                tmp[dl++] = Q[i];
            else
                tmp[dr--] = Q[i];
        } else {
            if (siz[dep][p1]+siz[dep][p2] >= Q[i].t)
                tmp[dl++] = Q[i];
            else
                tmp[dr--] = Q[i];
        }
    }

    for (int i=ql;i<=qr;i++) Q[i] = tmp[i];
    solve(ql,dl-1,vl,mid,dep+1);
    solve(dr+1,qr,mid+1,vr,dep+1);
}

int main() {
    n = rd(), m = rd();
    for (int i=1;i<=m;i++) a[i] = rd(), b[i] = rd();

    for (int i=1;i<=19;i++)
        for (int j=1;j<=n;j++)
            fa[i][j] = j, siz[i][j] = 1;

    q = rd();
    for (int i=1;i<=q;i++) {
        int x = rd(), y = rd(), t = rd();
        Q[i] = (HbFS){i, x, y, t};
    }
    solve(1,q,1,m,1);
    for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
    return 0;
}

E - Candy Piles

题意: N N 堆糖果,第 i i 堆糖果有 ai a i 个糖果。两个人进行游戏,每一轮可以进行如下操作之一:
1、每堆糖果拿一个。
2、取走最多那一堆糖果。
吃掉最后一个糖果的人判负,求先手胜负。
解答:
从大到小排序,前两种操作可以这么表示。
AtCoder Grand Contest 002 做题记录_第1张图片
将操作看成一条路径:
AtCoder Grand Contest 002 做题记录_第2张图片
然后看一看每个点的胜负:
AtCoder Grand Contest 002 做题记录_第3张图片
发现自左下向右上的对角线胜负关系相同

#include
#define N 500005
using namespace std;
int n,a[N],ans;
inline int rd() {   int r;scanf("%d",&r);return r;}
bool cmp(int p1,int p2) {return p1 > p2;}
int main(){
    n = rd();
    for (int i=1;i<=n;i++) a[i] = rd();
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++) if(i+1>a[i+1]) {
        for(int j=i+1;a[j]==i;j++) ans^=1;
        ans |= (a[i] - i) & 1;
        if (ans) puts("First"); else puts("Second");
        return 0;
    }
    return 0;
}

你可能感兴趣的:(AGC做题记录)