AtCoder Grand Contest 027

链接

A. Candy Distribution Again

skipped

B. Garbage Collector

skipped

C. ABland Yard

XJ 原题。。。

考虑到达一个点之后一定存在出边的充要条件就是存在从这个点连向 A 和 B 的点。

这样,我们只需要依次删去不满足条件的点即可。如果最后存在剩下的点就满足条件。

复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 500010
using namespace std;
char s[N];
int nxt[N<<1],to[N<<1],head[N],cnt;
int tot[N][2];
void add(int u,int v)
{
    nxt[++cnt]=head[u];
    to[cnt]=v;
    head[u]=cnt;
}
queue<int>q;
bool ban[N];
int main()
{
    int n,m;
    scanf("%d%d%s",&n,&m,s+1);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
        tot[u][s[v]-'A']++;tot[v][s[u]-'A']++;
    }
    for(int i=1;i<=n;i++)
    if(!tot[i][0] || !tot[i][1]) q.push(i),ban[i]=true;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(ban[v]) continue;
            tot[v][s[u]-'A']--;
            if(!tot[v][0] || !tot[v][1]) q.push(v),ban[v]=true;
        }
    }
    for(int i=1;i<=n;i++)
    if(!ban[i]){puts("Yes");return 0;}
    puts("No");
    return 0;
}

D. Modulo Matrix

构造题。

首先我们不妨黑白染色,钦定白点是较小的点,那么我们只需要一个黑点模相邻白点的值是定值即可。

为了保证不同,我们不妨钦定这个值是 1。那么黑点就应该是周围白点的 lcm 加 1。

为了这个值不重复,我们对每条主对角线和副对角线设置一个质数,然后每个白格数字是穿过它的两条对角线的乘积。

可以证明这样最大的数字只有 1014 级别。

复杂度 O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1010
#define ll long long
using namespace std;
int pr[N*10],tot;
bool p[N*10];
void init(int n=N*10-10)
{
    for(int i=2;i<=n;i++)
    {
        if(!p[i]) pr[++tot]=i;
        for(int j=1;j<=tot && pr[j]*i<=n;j++)
        {
            p[pr[j]*i]=true;
            if(i%pr[j]==0) break;
        }
    }
}
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
ll lcm(ll x,ll y){return x && y?x/gcd(x,y)*y:x+y;}
ll a[N][N];
int main()
{
    int n;
    scanf("%d",&n);
    if(n==2){puts("4 7\n23 10");return 0;}
    init();
    for(int i=1;i<=n;i++)
        for(int j=(~i&1)+1;j<=n;j+=2)
        a[i][j]=1ll*pr[(i+j)/2]*pr[n+(i-j)/2+(n+1)/2];
    for(int i=1;i<=n;i++)
        for(int j=(i&1)+1;j<=n;j+=2)
        a[i][j]=lcm(lcm(a[i-1][j],a[i+1][j]),lcm(a[i][j-1],a[i][j+1]))+1;
    for(int i=1;i<=n;i++,puts(""))
        for(int j=1;j<=n;j++) printf("%lld ",a[i][j]);
    return 0;
}

E. ABBreviate

由于这个操作没有群的性质(一个操作的逆操作不合法),所以没法用那种套路做。

考虑分析性质,可以发现如果令 A=1,B=2,那么操作不会导致字符串的所有数字值的和对 3 取模的结果改变。不妨称这个结果是这个字符串的值。

首先特判掉 ABABAB 这样的串。

可以证明,如果不是上述情况,且字符串 t 的值与 s 相等,且可以将 s 设置 t 个前缀,每个前缀的值与 t 的对应元素的值相同即可。

不妨记录上一次对 3 取模的结果的位置,这样就可以做到 O(1) 转移。

复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100010
#define mod 1000000007
using namespace std;
char s[N];
int f[N],g[3]={0,-1,-1};
int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1),p=0;
    bool hv=false;
    for(int i=2;i<=n;i++)
    if(s[i]==s[i-1]) hv=true;
    if(!hv){puts("1");return 0;}
    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        p=(p+s[i]-'a'+1)%3;
        f[i]=!p && i!=n; g[p]=i;
        if(~g[(p+1)%3]) (f[i]+=f[g[(p+1)%3]])%=mod;
        if(~g[(p+2)%3]) (f[i]+=f[g[(p+2)%3]])%=mod;
    }
    printf("%d\n",f[n]);
    return 0;
}

F. Grafting

首先假如原树已经同构直接特判。

否则我们直接枚举最后一个操作是什么。然后以该点为根,可以发现假如一个点和其祖先都被修改,该点一定在祖先前,且该点一定在被修改后的祖先后。

然后直接拓扑排序即可。复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define N 60
#define M N*6
#define inf 100000000
using namespace std;
int nxt[M<<1],to[M<<1],cnt;
void add(int head[],int u,int v)
{
    nxt[++cnt]=head[u];
    to[cnt]=v;
    head[u]=cnt;
}
int h1[N],h2[N],deg[N],in[N];
vector<int>g[N];
int f1[N],f2[N],n;
void dfs(int u,int f[],int head[],int p=0)
{
    f[u]=p;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==p) continue;
        dfs(v,f,head,u);
    }
}
queue<int>q;
inline bool diff(int x){return f1[x]!=f2[x];}
int solve()
{
    int c=0;
    for(int i=1;i<=n;i++)
    if(diff(i)) c++;
    else if(diff(f1[i])) return inf;
    for(int i=1;i<=n;i++) g[i].clear(),in[i]=0;
    for(int i=1;i<=n;i++)
    if(diff(i))
    {
        if(diff(f1[i])) g[i].push_back(f1[i]),in[f1[i]]++;
        if(diff(f2[i])) g[f2[i]].push_back(i),in[i]++;
    }
    for(int i=1;i<=n;i++)
    if(diff(i) && !in[i]) q.push(i);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int v:g[u])
        {
            in[v]--;
            if(!in[v]) q.push(v);
        }
    }
    for(int i=1;i<=n;i++)
    if(diff(i) && in[i]) return inf;
    return c;
}
void clear()
{
    memset(h1,0,sizeof(h1));memset(h2,0,sizeof(h2));
    cnt=0;memset(deg,0,sizeof(deg));
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t --> 0)
    {
        clear();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(h1,u,v),add(h1,v,u);++deg[u],++deg[v];
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(h2,u,v),add(h2,v,u);
        }
        dfs(1,f1,h1);dfs(1,f2,h2);
        bool can=true;
        for(int i=1;i<=n;i++)
        if(f1[i]!=f2[i]) can=false;
        if(can){puts("0");continue;}
        int ans=inf;
        for(int i=1;i<=n;i++)
        if(deg[i]==1)
        {
            dfs(i,f2,h2);
            for(int j=1;j<=n;j++)
            if(i!=j)
            {
                dfs(j,f1,h1);f1[j]=i;f1[i]=0;
                ans=min(ans,solve()+1);
            }
        }
        printf("%d\n",ans>n?-1:ans);
    }
    return 0;
}
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编程运行原理
点击右上角即可分享
微信分享提示