AtCoder Grand Contest 033

链接

A. Darker and Darker

skipped

B. LRUD Game

skipped

C. Removing Coins

博弈论结论题。首先硬币多少没有关系,所以题面就变成选择一个点,然后删去以它为根时的叶子节点。

可以发现,无论选取哪一个点都会导致直径至少减少1。如果选取了非直径端点的点则会导致直径减少2。

显然当直径等于 0 时没有点可以选。也就是说,除了最后一步之外,两个人都可以选择直径 -2 或 -1。

最后一步有可能只存在两个点,这种情况下只能一个个选。也就是说 2 是先手必败。

这样就可以推出,假如长度除 3 的余数等于 0 或 1,那么先手把长度取为 2,然后取 3-后手选择的数字 即可。

反之后手必胜。

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010
using namespace std;
int nxt[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v)
{
    nxt[++cnt]=head[u];
    to[cnt]=v;
    head[u]=cnt;
}
void dfs(int u,int p,int &t,int &l)
{
    t=u;l=1;
    for(int i=head[u];i;i=nxt[i])
    {
        int t1=0,l1=0,v=to[i];
        if(v==p) continue;
        dfs(v,u,t1,l1);
        if(l1+1>l) l=l1+1,t=t1;
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    int t=0,l=0;
    dfs(1,0,t,l);
    dfs(t,0,t,l);
    puts(l%3==2?"Second":"First");
    return 0;
}

D. Complexity

E. Go around a Circle

首先考虑钦定第一个是红的,否则翻转红蓝结果一定不变。

然后如果所有都是红的,那么结果就是不能有一个点连出两条蓝边,直接递推即可。

否则仍然还是不能有一个点连出两条蓝边,同时两个蓝边之间至少的红边数为奇数。

考虑连续的 R 的最小值,可以发现任何两个蓝边之间的红边数不能大于这个值。然后按照这两个条件 dp 即可,加上前缀和优化。

复杂度 O(n+m)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010
#define mod 1000000007
using namespace std;
int f[N],a[N],nxt[N];
char s[N];
int ksm(int a,int b=mod-2)
{
    int r=1;
    for(;b;b>>=1)
    {
        if(b&1) r=1ll*r*a%mod;
        a=1ll*a*a%mod;
    }
    return r;
}
int main()
{
    int n,m;
    scanf("%d%d%s",&n,&m,s+1);
    for(int i=1;i<=m;i++) a[i]=s[i]==s[1];nxt[m+1]=m+1;
    for(int i=m;i;i--) nxt[i]=a[i]?nxt[i+1]:i;
    if(nxt[1]==m+1)
    {
        f[0]=1,f[1]=2;
        for(int i=2;i<=n;i++) f[i]=(f[i-1]+f[i-2])%mod;
        if(n==1) puts("1");
        else if(n==2) puts("3");
        else printf("%d\n",(f[n-1]+f[n-3])%mod);
        return 0;
    }
    if(n&1){puts("0");return 0;}
    int t=nxt[1];
    for(int i=1;i<=m;i++)
    if(nxt[i]!=m+1 && !a[i-1] && (nxt[i]-i)%2) t=min(t,nxt[i]-i);
    n=n/2,t=(t+1)/2;
    int v=0;
    for(int i=1;i<=n;i++)
    {
        if(i>t) f[i]=v=(v-f[i-t-1]+mod)%mod;
        else f[i]=(v+i*2)%mod;
        v=(v+f[i])%mod;
    }
    printf("%d\n",f[n]);
    return 0;
}

F. Adding Edges

考虑如果最后的三个点 a,b,c 是有序的,那么我们可以处理依次加入一条边。

然后考虑记 rx,y 表示以 x 为根 y 有连边的最近的祖先。对于每一条边 (x,y)

如果 rx,y=y 那么不用加入。否则如果 rx,y 存在那么加入 (rx,y,y)

否则我们暴力 dfs x 的整颗子树让所有点的父亲指向 y,对于 y 同理,然后再加入 (x,y)

然后对于统计答案直接统计每个点为根时与其他点是否有边即可。

复杂度 O(n2+nm)

posted @   Flying2018  阅读(7)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示