AtCoder Grand Contest 017做题记录

诶最后三道题+第三题的部分分收场了
感觉这场比赛没怎么动脑子
不过也是NOI前最后一场AGC了吧,估计AtCoder的rating以后没机会变了

A - Biscuits

题意:
N 袋饼干,第 i 袋饼干大小为 Ai ,询问有多少种方案使得选出来的饼干总数模2为p
N50Ai100
解答:
Fi,j 表示前 i 袋饼干,选出来总和模2为 j 的方案数。

#include 
using namespace std;
typedef long long LL;
int n,k,a[100050];
LL F[100050][2];
int main() {
    scanf("%d%d",&n,&k);
    for (int _=1;_<=n;_++) scanf("%d",&a[_]);
    F[0][0] = 1LL;
    for (int _=1;_<=n;_++) {
        int t = a[_]&1;
        F[_][0] = F[_-1][0] + F[_-1][0^t];
        F[_][1] = F[_-1][1] + F[_-1][1^t];
    }
    cout << F[n][k] << endl;

    return 0;       
}

B - Moderate Differences

题意:
一列有 N 个数,第一个数为 A ,最后一个数为 B ,第 2 ~ N1 个数未知。询问是否存在一种填数方案使得任意相邻两个数之差的绝对值 [C,D]
N500000A,B,C,D109
做法:
爆枚有多少个数的差为正数,多少个为负数。
判断一下有没有交即可。

#include 
using namespace std;
typedef long long LL;
int n,a,b,c,d,flag;
int main() {
    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
    for (int i=0;iint t = n-i-1;
        LL ll = a + 1LL * i * c;
        LL rr = a + 1LL * i * d;

        LL lll = b + 1LL * t * c;
        LL rrr = b + 1LL * t * d;

        LL tl = max(ll, lll);
        LL tr = min(rr, rrr);
        if (tl <= tr) flag = 1;
    }   
    puts(flag?"YES":"NO");
    return 0;       
}

C - Snuke and Spells

题意:
N 张牌,每张牌上有一个数字。进行如下操作:

  • 修改若干张牌上的数字
  • 若当前有 k 张牌,则所有牌上写了 k 的牌全部消失

修改最少的数字,使得所有的牌都消失
M 次单点修改牌的数字的操作,每次操作后询问。
N,M200000
解答:
若有 ti 张写着 i 的牌,将它看成 [iti+1,i] 区间的线段。
未被线段覆盖的点的个数即为答案。

    #include 
    #define N 200050
    using namespace std;
    int n,m,a[N],t[N],F[N],ans;
    inline int rd() {
    int x=0,f=1;char ch=getchar();
    while (ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
    }
    int main() {
    n = rd(), m = rd();
    for (int _=1;_<=n;++_) a[_] = rd();
    for (int _=1;_<=n;_++) t[a[_]]++;
    for (int _=1;_<=n;_++)
    for (int j=0;jif (_-j>0) F[_-j]++;
    for (int _=1;_<=n;_++) if (!F[_]) ans++;
    while (m--) {
    int x = rd(), y = rd();
    if (a[x]-t[a[x]]+1 >=1 && --F[ a[x]-t[a[x]]+1 ] == 0) ans++;
    t[ a[x] ]--;
    a[x] = y;
    t[ a[x] ]++;
    if (a[x]-t[a[x]]+1 >=1 && ++F[ a[x]-t[a[x]]+1 ] == 1) ans--;
    printf("%d\n",ans);
    }
    return 0;
    }

D - Game on Tree

题意:
给定一棵N个点的有根树,两个人轮流删掉一条边和该边链接的子树,无法操作的人输。求最后是谁赢。
解答:
IOI2009中国国家集训队论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》

    #include 
    #define N 1000500
    using namespace std;

    vector<int> E[N];
    int sg[N],n;
    inline int rd() {int r;scanf("%d",&r);return r;}
    void dfs(int u,int f) {
    sg[u] = 0;
    for (int i=0;i<(int)E[u].size();i++) {
    int v = E[u][i]; if (v == f) continue;
    dfs(v,u); sg[u] ^= sg[v]+1;
    }
    }

    int main() {
    n = rd();
    for (int i=1;iint a = rd(), b = rd();
    E[a].push_back(b);
    E[b].push_back(a);  
    }
    dfs(1,1);
    puts(sg[1] ? "Alice" : "Bob");
    return 0;
    }

E - Jigsaw

题意:
给定若干个图形,每个图形由三个长方形拼成。是否存在一种方案将所有的图形拼在一列,并且满足所有图形的底边靠近地面,且中间没有空隙。
解答:
把每个图形看成一条边,转化为寻找一条特殊的路径

#include 
#define N 2000500
using namespace std;
int n,m,fa[N],vis[N],D[N],C[N];
int gf(int x) {return fa[x]==x?x:fa[x]=gf(fa[x]);}
inline int rd() {int r;scanf("%d",&r);return r;}
int main() {
    n = rd(), m = rd();

    for (int i=1;i<=1000;i++) fa[i] = i;
    for (int _=1;_<=n;_++)  {
        int x, y,a,b,c,d;
        a = rd(), b = rd(), c = rd(), d = rd();
        x=!c?a:-c; x+=500;
        y=!d?-b:d; y+=500;
        fa[ gf(x) ] = gf(y);
        D[x]++, D[y]--, vis[x] = 1;
    }

    int flag = 1;
    for (int i=1;i<500;i++) D[i]>0 ? flag=0 :0;
    for (int i=501;i<=1000;i++) D[i]<0 ? flag=0 :0;
    for (int i=1;i<=1000;i++) vis[gf(i)] |= vis[i];
    for (int i=1;i<=1000;i++) if (D[i]) C[gf(i)] = 1;
    for (int i=1;i<=1000;i++) if (fa[i]==i && !C[i] && vis[i]) flag = 0;
    puts(flag?"YES":"NO");
    return 0;
}

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