AtCoder Grand Contest 034

链接

C. Tests

直接二分答案 s,考虑最优情况下一定会让 ai>bi 部分取 ci=ri,否则取 ci=li。且至多只有一个数字满足 ai<X。直接枚举哪一个数字,复杂度 O(nlogn)

D. Manhattan Max Matching

考虑跑费用流。可以发现的一点是 |xx|=max(xx,xx),所以直接建四个关键点,然后每个红点点 (x,y) 分别连 x+y,xy,x+y,xy,边权 +

蓝点同理。复杂度 O(n3C),实际上压根跑不满。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
typedef long long ll;
#define N 30010
#define M 100010
#define inf 100000000000000ll
using namespace std;
struct road{
    int nxt,to,f;
    ll w;
}r[M<<1];
int head[N],cnt=1;
void add(int u,int v,int f,ll w)
{
    r[++cnt]=(road){head[u],v,f,w};head[u]=cnt;
    r[++cnt]=(road){head[v],u,0,-w};head[v]=cnt;
}
int all=0;
ll dis[N];int pre[N],bef[N];bool in[N];
queue<int>q;
bool spfa(int s,int t)
{
    for(int i=1;i<=all;i++) dis[i]=inf,pre[i]=0;
    q.push(s);dis[s]=0;
    in[s]=true;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        in[u]=false;
        for(int i=head[u];i;i=r[i].nxt)
        if(r[i].f)
        {
            int v=r[i].to;
            if(dis[v]<=dis[u]+r[i].w) continue;
            dis[v]=dis[u]+r[i].w;
            pre[v]=u;bef[v]=i;
            if(!in[v]) q.push(v),in[v]=true;
        }
    }
    return pre[t];
}
ll MCMF(int s,int t)
{
    ll res=0;
    while(spfa(s,t))
    {
        int w=100000000;
        for(int u=t;u!=s;u=pre[u]) w=min(w,r[bef[u]].f);
        res+=1ll*w*dis[t];
        for(int u=t;u!=s;u=pre[u]) r[bef[u]].f-=w,r[bef[u]^1].f+=w;
    }
    return res;
}
int main()
{
    int n;
    scanf("%d",&n);
    int o1=n*2+1,o2=o1+1,o3=o2+1,o4=o3+1;
    int s=o4+1,t=s+1;all=t;
    for(int i=1;i<=n;i++)
    {
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        add(s,i,w,0);
        add(i,o1,w,x+y);add(i,o2,w,x-y);add(i,o3,w,-x+y);add(i,o4,w,-x-y);
    }
    for(int i=1;i<=n;i++)
    {
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        add(i+n,t,w,0);
        add(o1,i+n,w,-x-y);add(o2,i+n,w,-x+y);add(o3,i+n,w,x-y);add(o4,i+n,w,x+y);
    }
    printf("%lld",-MCMF(s,t));
    return 0;
}

E. Complete Compress

枚举一个根。可以发现最优情况下一定是每次移动两个不互为祖先关系的点。

考虑树形 dp,fi 表示 i 子树内处理之后所有点的深度和最小值。

特判奇偶性后直接 dp。复杂度 O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2010
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;
}
int a[N];char s[N];
int f[N],siz[N];
int dfs(int u,int p)
{
    siz[u]=a[u];f[u]=0;
    int mx=0,mw=0;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==p) continue;
        int w=dfs(v,u);siz[u]+=siz[v];
        f[u]+=f[v]+siz[v];
        if(!mx || f[v]>f[mx]) mx=v,mw=w;
    }
    if(!mx) return 0;
    return max(f[u]&1,(mw+siz[mx])-(f[u]-f[mx]-siz[mx]));
}
int main()
{
    int n;
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) a[i]=s[i]=='1';
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    int ans=n*n;
    for(int i=1;i<=n;i++)
        if(!dfs(i,0)) ans=min(ans,f[i]);
    printf("%d\n",ans>=n*n?-1:ans/2);
    return 0;
}

F. RNG and XOR

考虑列方程,令 fi 表示 0i 的期望步数,显然有 fi=1+jfjpij,f0=0

考虑集合幂级数,即 F+2n=I+FP,处理一下即 F=2nIA1

直接 FWT,复杂度 O(n2n)

#include<iostream>
#include<cstdio>
#include<cstring>
#define M 1<<18
#define mod 998244353
using namespace std;
const int inv2=(mod+1)/2;
int f[M],g[M],n,m;
int ksm(int a,int b=mod-2)
{
    int r=1;
    for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
    return r;
}
void fwt(int f[],int op=1)
{
    for(int i=1;i<m;i<<=1)
        for(int j=0;j<m;j+=i<<1)
            for(int k=j;k<j+i;k++)
            {
                int x=f[k],y=f[i+k];
                f[k]=(x+y)%mod;f[i+k]=(x-y+mod)%mod;
                if(op==-1) f[k]=1ll*f[k]*inv2%mod,f[i+k]=1ll*f[i+k]*inv2%mod;
            }
}
int main()
{
    scanf("%d",&n);
    m=1<<n;
    int s=0;
    for(int i=0;i<m;i++) scanf("%d",&g[i]),s=(s+g[i])%mod;
    s=ksm(s);
    for(int i=0;i<m;i++) g[i]=1ll*g[i]*s%mod;
    g[0]--;
    for(int i=1;i<m;i++) f[i]=mod-1;
    f[0]=m-1;
    fwt(f);fwt(g);
    for(int i=0;i<m;i++) f[i]=1ll*f[i]*ksm(g[i])%mod;
    fwt(f,-1);
    for(int i=0;i<m;i++) printf("%d\n",(f[i]-f[0]+mod)%mod);
    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编程运行原理
点击右上角即可分享
微信分享提示