ABC221G 题解

ABC221G 题解

upd:2025.9.10 你是不是其实是假的

原来上一次写博客已经是 thuwc 了么,为了防止下一篇就是省选游记 赶紧写篇博客证明我还活着

发现问题很像一个背包啊,但是一个点有四个状态,二维背包显然没有一个合理的复杂度通过此题

发现限制 \(x+y\)\(x-y\) 和分别限制 \(x\)\(y\)是等价的,而这样可以让两边背包分别做,做完合并,大概等价于绕 \((0,0)\) 旋转 \(\frac{\pi}{4}\) 这样子

所以做两遍背包之后记录方案,最后合并就完了

考虑怎么做这个背包

我们考虑 Uplifting Excursion 的做法,先尽量多的选,然后调整即可

首先如果合法的话一定有一种方案能让我们所有转移都在 \([T-D,T+D]\) 之间完成所有转移

因为我们只关心可达性,没有权值,所以每个点第一次到达的状态就是最优状态

记录每个点的方案,bfs暴力尝试扩展即可,复杂度 \(O(nD)\)

代码非常好写!

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
const llt N=2010,D=3600;
llt n,A,B,d[N];bool vis[N<<2],ans=1;
bitset<N> s[N<<2],bs,x,y;queue<llt> qu;
void bfs(llt now)
{
    qu.push(now);
    while(!qu.empty())
    {
        now=qu.front();qu.pop();
        for(int i=1;i<=n;i++)
            if(s[now][i])   {if(now-2*d[i]>=0&&!vis[now-2*d[i]]) vis[now-2*d[i]]=1,s[now-2*d[i]]=s[now],s[now-2*d[i]].flip(i),qu.push(now-2*d[i]); }
            else    {if(now+2*d[i]<=2*D&&!vis[now+2*d[i]]) vis[now+2*d[i]]=1,s[now+2*d[i]]=s[now],s[now+2*d[i]].flip(i),qu.push(now+2*d[i]); }
    }
}
bool solve(llt v)
{
    llt sum=0;bs=0;memset(vis,0,sizeof(vis));for(int i=0;i<=2*D;i++) s[i]=0; 
    for(int i=1;i<=n;i++)   sum-=d[i];
    if(sum>v)   return 0;
    for(int i=1;i<=n;i++){bs[i]=1;sum+=2*d[i];if(sum>=v)   break;}
    if(sum<v)   return 0;
    s[sum-v+D]=bs;bfs(sum-v+D);
    return vis[D];
}
int main()
{
    #ifdef LOCAL           
        freopen("2.in","r",stdin);         
        freopen("2.out","w",stdout);             
    #endif
    scanf("%lld%lld%lld",&n,&A,&B);
    for(int i=1;i<=n;i++)   scanf("%lld",&d[i]);
    ans&=solve(A+B);x=s[D];ans&=solve(A-B);y=s[D];
    if(ans)   
    {
        puts("Yes");
        for(int i=1;i<=n;i++)
            if(x[i]&&y[i])    printf("R");
            else if(x[i])     printf("U");
            else if(y[i])     printf("D");
            else printf("L");
    }
    else puts("No");
    return 0;
}
posted @ 2025-02-23 16:48  wang54321  阅读(41)  评论(2)    收藏  举报