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;
}
相关推荐
词元Max1 小时前
4.2 决策树与随机森林
算法·决策树·随机森林
郝学胜-神的一滴1 小时前
Qt 高级开发 022:栅格布局深度实战
开发语言·c++·qt·软件构建·用户界面
basketball6161 小时前
设计模式入门:3. 装饰器模式详解 C++实现
c++·设计模式·装饰器模式
菜菜的顾清寒1 小时前
力扣HOT100(51) 动态规划-单词拆分
算法·leetcode·动态规划
风筝在晴天搁浅1 小时前
剑指Offer LCR 143.子结构判断
算法
程序大视界1 小时前
【C++ 从基础到项目实战】C++(三):函数进阶——重载、回调、递归与默认参数
开发语言·c++·cpp
西梅汁1 小时前
C++ 线程间通信(二)
c++
咖啡八杯1 小时前
GoF设计模式——装饰模式
java·算法·设计模式·装饰器模式
装不满的克莱因瓶1 小时前
实现矩阵的点积:从数学原理到 NumPy 实战
人工智能·线性代数·算法·机器学习·矩阵·numpy