AtCoder Beginner Contest 453

D - Go Straight

思路:条件判断的BFS,注意不要存储完整路径字符串 ,改为 记录前驱状态,到达终点后反向回溯构建路径。

开三个数组记录前驱:

cpp 复制代码
int pre_x[N][N][4];   // 前驱的 x 坐标
int pre_y[N][N][4];   // 前驱的 y 坐标
int pre_dir[N][N][4]; // 前驱的方向(0~3),起点设为 -1
int move_dir[N][N][4];// 从父状态到当前状态所用的方向

Code:

cpp 复制代码
using aii=array<int,3>;
const int N = 5e6,mod=998244353;
typedef pair<int,int> PII;
#define fi first
#define se second
typedef pair<aii,string> pai;
int n,m;

bool st[1005][1005][4];
int ne[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char a[1005][1005];
int sx,sy,ex,ey;
string s[4]={"R","L","D","U"};
int dist[1005][1005][4];
int prex[1005][1005][4],prey[1005][1005][4],predir[1005][1005][4],movedir[1005][1005][4];
bool ok(int tx,int ty)
{
   if(tx>=0&&tx<n&&ty>=0&&ty<m)
      {
       return true;
      }
      return false;
}

void print(int x,int y,int i)
{
    if(predir[x][y][i]==-1)
    {
        cout<<s[i];
        return ;
    }
    print(prex[x][y][i],prey[x][y][i],predir[x][y][i]);
    cout<<s[i];
}
void Dijkstra()
{
   queue<aii> heap;
   for(int i=0;i<4;i++)
    {
      int tx=sx+ne[i][0],ty=sy+ne[i][1];
       st[sx][sy][i]=1;
      if(tx>=0&&tx<n&&ty>=0&&ty<m)
      {
          
        if(a[tx][ty]!='#')
        {
            st[tx][ty][i]=1;
            heap.push({tx,ty,i});
            dist[tx][ty][i]=1;
            prex[tx][ty][i]=sx;
            prey[tx][ty][i]=sy;
            predir[tx][ty][i]=-1;
            movedir[tx][ty][i]=i;
        }
          
      }
    }

    while(heap.size())
    {
      auto [x,y,c]=heap.front();heap.pop();
        //auto [x,y,c]=arr;
     
      if(a[x][y]=='G')
      {
        cout<<"Yes"<<endl;
        print(x,y,c);
        return ;
      }

  //    if(st[x][y][c]) continue;
      
      if(a[x][y]=='.')
      {
        for(int i=0;i<4;i++)
        {
          int tx=x+ne[i][0],ty=y+ne[i][1];
          if(ok(tx,ty)&&a[tx][ty]!='#'&&!st[tx][ty][i]&&dist[x][y][c]+1<=N)
          {
          
              st[tx][ty][i]=1;
               prex[tx][ty][i]=x;
            prey[tx][ty][i]=y;
            predir[tx][ty][i]=c;
            movedir[tx][ty][i]=i;
            heap.push({tx,ty,i});
          }
        }
      }
      else if(a[x][y]=='o')
      {
        int tx=x+ne[c][0],ty=y+ne[c][1];
        if(ok(tx,ty)&&a[tx][ty]!='#'&&!st[tx][ty][c]&&dist[x][y][c]+1<=N)
        {
  
            st[tx][ty][c]=1;
             prex[tx][ty][c]=x;
            prey[tx][ty][c]=y;
            predir[tx][ty][c]=c;
            movedir[tx][ty][c]=c;
          heap.push({tx,ty,c});
        }
      }
      else if(a[x][y]=='x')
      {
        for(int i=0;i<4;i++)
        {
          if(i==c) continue;
          int tx=x+ne[i][0],ty=y+ne[i][1];
          if(ok(tx,ty)&&a[tx][ty]!='#'&&!st[tx][ty][i]&&dist[x][y][c]+1<=N)
          {

              st[tx][ty][i]=1;
               prex[tx][ty][i]=x;
            prey[tx][ty][i]=y;
            predir[tx][ty][i]=c;
            movedir[tx][ty][i]=i;
            heap.push({tx,ty,i});
          }
        }
      }

    }
    cout<<"No";
}
void solve()
{
   cin>>n>>m;
   for(int i=0;i<n;i++)
    for(int j=0;j<m;j++)
    {
      cin>>a[i][j];
      if(a[i][j]=='S') sx=i,sy=j;
      else if(a[i][j]=='G') ex=i,ey=j;
    }
    Dijkstra();
}

E - Team Division

思路:差分求前缀和

1.只能选A Li Ri

2.只能选B n-Ri n-Li

3.A和B都可以 max(Li,n-Ri) min(Ri,n-Li)

对三个数组进行差分求前缀和

枚举A队人数

x=cntAi-cntCi表示A队最多为i人的情况下有x人只能选A队

y=cntBi-cntCi表示A队最多为i人的情况下有y人只能选B队

z=cntCi表示有z人可以去任意一队

如果三者加起来等于n方案数为C(z,i-x)

Code:

cpp 复制代码
int fact[N],infact[N];

int qmi(int a,int b)
{
  int res=1;
  while(b)
  {
    if(b&1) res=res*a%mod;
    b>>=1;
    a=a*a%mod;
  }
  return res;
}
int C(int x,int y)
{
  if(x<0||y<0||x<y) return 0;
  return fact[x]*infact[y]%mod*infact[x-y]%mod;
}
void solve()
{
  fact[0]=infact[0]=1;
  for(int i=1;i<N;i++)
  {
    fact[i]=fact[i-1]*i%mod;
    infact[i]=infact[i-1]*qmi(i,mod-2)%mod;
  }
  int n;cin>>n;
   vector<int> cnt1(n+5,0),cnt2(n+5,0),cnt3(n+5,0);
   for(int i=0;i<n;i++)
   {
    int l,r;cin>>l>>r;
    cnt1[l]++,cnt1[r+1]--;
    cnt2[n-r]++,cnt2[n-l+1]--;
    int l1=max(l,n-r),r1=min(r,n-l);
    if(l1<=r1) cnt3[l1]++,cnt3[r1+1]--;
   }
   for(int i=1;i<=n;i++)
   {
    cnt1[i]+=cnt1[i-1];
    cnt2[i]+=cnt2[i-1];
    cnt3[i]+=cnt3[i-1];
   }
   int ans=0;
   for(int i=1;i<=n;i++)
   {
    int x=cnt1[i]-cnt3[i],y=cnt2[i]-cnt3[i];
    if(x+y+cnt3[i]==n) ans=(ans+C(cnt3[i],i-x))%mod;
   }
   cout<<ans;
}
相关推荐
想做小南娘,发现自己是女生喵19 分钟前
【无标题】
数据结构·算法
Kx_Triumphs2 小时前
HDU4348 To the moon(主席树区间修改模板)
算法·题解
旖-旎2 小时前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
Darkwanderor3 小时前
对Linux的进程控制的研究
linux·运维·c++
云泽8083 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
轻颂呀3 小时前
约瑟夫环问题
算法
REDcker3 小时前
libdatachannel 快速入门
c++·webrtc·datachannel
科技大视界5 小时前
投资AI项目,传统尽调不够用了——李章虎律师拆解算法、数据、算力三大雷区
人工智能·算法·数据挖掘
second605 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++