AtCoder Grand Contest 019

链接

C. Fountain Walk

首先毛估估一下,可以发现我们一定不会为了蹭柱子而绕远路。而在最优策略中每经过一次柱子一定会向另一个方向转。

所以直接统计路上最多能蹭到几次柱子,这就是最长上升子序列。

特别的可能会出现路被柱子堵死的情况,这样需要绕过一根柱子,特判额外贡献。

复杂度 O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200010
#define M 200000000
#define db double
using namespace std;
const db pi=acos(-1),dt=10*(2-pi/2);
struct node{
    int x,y;
    bool operator <(const node a)const{return x<a.x;}
}p[N];
int q[N],qt;
int main()
{
    int x1,y1,x2,y2,n;
    scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&n);
    bool tx=0,ty=0;
    if(x1>x2) x1=M-x1,x2=M-x2,tx=true;
    if(y1>y2) y1=M-y1,y2=M-y2,ty=true;
    int tt=0;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(tx) x=M-x;if(ty) y=M-y;
        if(x1<=x && x<=x2 && y1<=y && y<=y2) p[++tt]=(node){x,y};
    }
    sort(p+1,p+tt+1);
    db d=(x2-x1+y2-y1)*100.0;
    memset(q,0x3f,sizeof(q));
    for(int i=1;i<=tt;i++)
    {
        int l=lower_bound(q+1,q+tt+1,p[i].y)-q;
        q[l]=p[i].y;
    }
    int res=0;
    for(int i=1;i<=tt;i++)
    if(q[i]<=M) res++;
    if(res==x2-x1+1 || res==y2-y1+1) d+=5*pi;
    printf("%.11lf",d-dt*res);
    return 0;
}

D. Shift and Flip

首先考虑贪心,最后一定是往某个方向转一定位置,然后往一直另一个方向转。

可以证明这样一定是最优的。最优方案就是总位移加上需要改变的颜色数。

考虑枚举最后的对应位置,那么一个需要改变的点需要在转动的过程中遇到 1 才行。

直接处理出每个点向左向右最近的黑点位置。总复杂度 O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2010
using namespace std;
char s[N],t[N];
int l[N],r[N],mx[N],ans;
void solve(int n)
{
    // printf("%s\n%s\n",s,t);
    for(int i=0;i<n;i++)
    {
        for(r[i]=0;t[(i+r[i])%n]!='1';r[i]++);
        for(l[i]=0;t[(i-l[i]+n)%n]!='1';l[i]++);
    }
    for(int i=0;i<n;i++)
    {
        memset(mx,0,sizeof(mx));
        int res=0,m=0;
        for(int j=0;j<n;j++)
        if(s[j]!=t[(i+j)%n])
        {
            res++;
            mx[l[j]]=max(mx[l[j]],r[j]);
        }
        for(int j=n-1;j>=0;j--) ans=min(ans,2*j+m+abs(m-i)+res),m=max(m,mx[j]);
        ans=min(ans,res+m*2+i);
    }
}
int main()
{
    scanf("%s%s",s,t);
    int n=strlen(s);ans=2*n;
    bool zs=true,zt=true;
    for(int i=0;i<n;i++) if(s[i]=='1') zs=false;
    for(int i=0;i<n;i++) if(t[i]=='1') zt=false;
    if(zt){puts(zs?"0":"-1");return 0;}
    solve(n);reverse(s,s+n);reverse(t,t+n);solve(n);
    printf("%d\n",ans);
    return 0;
}

E. Shuffle and Swap

考虑可以把题目转化为:有 3 种点,其中第一种点可以连出一条边,第二种点可以连出并连入各一条边,第三种点可以连入一条边。

可以发现除了第二种点组成的环之外,其余的点只要确定了连边方案,那么连边顺序也是唯一的。第二种点组成的环的所有方案恰好是 (n!)2

所以考虑用 fi,j 表示选了 i 个二类点,j 组一三类点的方案数。要求 j=n,那么剩下的二类点就可以任意选择。

复杂度 O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10010
#define M 5010
#define mod 998244353
using namespace std;
int fac[N],inv[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;
}
void init(int n=N-10)
{
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
    inv[n]=ksm(fac[n]);
    for(int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
int C(int x,int y){return x<y?0:1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;}
char s[N],t[N];
int s1,s2;
int f[M][N];
int main()
{
    scanf("%s%s",s+1,t+1);
    int n=strlen(s+1);
    init();
    for(int i=1;i<=n;i++)
    if(s[i]==t[i]) s1+=s[i]=='1';
    else s2+=s[i]=='1';
    for(int i=0;i<=s2;i++) f[i][0]=1ll*fac[i]*fac[i]%mod;
    for(int i=1;i<=s2;i++)
        for(int j=1;j<=s1;j++)
        f[i][j]=(1ll*f[i][j-1]*i%mod*j%mod+1ll*f[i-1][j]*i%mod*i%mod)%mod;
    int ans=0;
    for(int i=0;i<=s1;i++) ans=(ans+1ll*f[s2][s1-i]*fac[i]%mod*fac[i]%mod*C(s1,i)%mod*C(s1+s2,i)%mod)%mod;
    printf("%d\n",ans);
    return 0;
}

F. Yes or No

好水的 F

考虑选择的策略应该是怎样的。显然如果对的比错的多应该选对,否则选错。这样可以发现如果没有越过中间部分,答案就是 max(n,m)

考虑越过中间部分即对错一样时我们一定有 12 的概率选对。可以发现无论这次对不对,都不会影响那 max(n,m) 部分的答案。

所以直接用每个点被经过的次数和除以总方案数乘 2 就是这部分的贡献。

最后加上 max(n,m) 即可。复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define N 200010
#define M 800010
#define inf 100000000
using namespace std;
int nxt[M<<1],to[M<<1],w[M<<1],head[N],cnt=1;
void add(int u,int v,int f)
{
    nxt[++cnt]=head[u];to[cnt]=v;
    w[cnt]=f;head[u]=cnt;
}
void adde(int u,int v,int w1=inf,int w2=0){add(u,v,w1);add(v,u,w2);}
int all,dep[N],cur[N];
queue<int>q;
bool bfs(int s,int t)
{
    for(int i=1;i<=all;i++) dep[i]=0,cur[i]=head[i];
    q.push(s);dep[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=nxt[i])
        if(w[i] && !dep[to[i]]) dep[to[i]]=dep[u]+1,q.push(to[i]);
    }
    return dep[t];
}
int dfs(int u,int t,int flow=inf)
{
    if(u==t || !flow) return flow;
    int res=0;
    for(int &i=cur[u];i;i=nxt[i])
    {
        int v=to[i],f;
        if(dep[v]==dep[u]+1 && (f=dfs(v,t,min(flow,w[i]))))
        {
            flow-=f,res+=f;
            w[i]-=f,w[i^1]+=f;
            if(!flow) break;
        }
    }
    return res;
}
int dinic(int s,int t){int res=0;while(bfs(s,t)) res+=dfs(s,t);return res;}
int s,t;
int id[N],ax[N],ay[N],tt;
void dfs(int u)
{
    ++tt;
    for(int i=head[u];i;i=nxt[i])
    if(w[i])
    {
        int v=to[i];
        if(v==s || id[v]) continue;
        id[v]=u;
        for(int j=head[v];j;j=nxt[j])
        if(w[j])
        {
            ax[v]=u,ay[v]=to[j];
            dfs(to[j]);
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);s=2*n,t=s+1;all=t;
    for(int i=1;i<=n;i++) adde(s,i,1);
    for(int i=1;i<n;i++) adde(i+n,t,1);
    for(int i=1;i<n;i++)
    {
        int c,a;
        scanf("%d",&c);
        while(c --> 0) scanf("%d",&a),adde(a,i+n,1);
    }
    if(dinic(s,t)!=n-1){puts("-1");return 0;}
    for(int i=head[s];i;i=nxt[i])
    if(w[i]){dfs(to[i]);break;}
    if(tt!=n){puts("-1");return 0;}
    for(int i=n+1;i<n*2;i++) printf("%d %d\n",ax[i],ay[i]);
    return 0;
}
posted @   Flying2018  阅读(14)  评论(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编程运行原理
点击右上角即可分享
微信分享提示