Atcoder Yahoo Programming Contest 2019 簡要題解

A-C

直接放代碼吧。數組

A

int n,k;
int main()
{
  n=read();k=read();
  puts(k<=(n+1)/2?"YES":"NO");
  return 0;
}

B

int d[N];pair<int,int>s[10];
int main()
{
  for(int i=1,u,v;i<=3;i++){
    u=read();v=read();
    s[i].first=u;s[i].second=v;
    d[u]++;d[v]++;
  }
  sort(s+1,s+3+1);
  for(int i=2;i<=3;i++)if(s[i]==s[i-1])return puts("NO"),0;
  for(int i=1;i<=4;i++)if(d[i]>=3)return puts("NO"),0;
  return puts("YES"),0;
}

C

int main()
{
  int k=read(),a=read(),b=read();ll ans=0;
  if(b<=a+2||k<=a-1)printf("%d\n",k+1);
  else{
    k-=a-1;ans=a;if(k&1)k--,ans++;
    printf("%lld\n",ans+1ll*(k/2)*(b-a));
  }
  return 0;
}

D - Ears

zsy在一條\([0,L]\)的數軸上來回走路。
zsy能夠任選\([0,L]\)中的整點做爲起點和終點,而且zsy走路時只能在整數位置(\(0,1,2,...,L\))調整方向。
每當zsy向左或向右通過一條\([i,i+1]\ (i\in[0,L))\)的線段時,zsy就會往這條線段的中間放上一個球。
當zsy走完路後,yyb會來到這條數軸。她會進行若干次操做:打爆一個球或在一條線段的中間放上一個球。
如今給出數軸每條線段中間最終球的個數\(a_1,...,a_n\),求出zsy的一種行走方式,使得yyb的操做次數最小。spa

由於zsy能夠反覆橫跳來回地走,因此能夠把\(a_i\)減去若干個2,最後只剩下\(0,1,2\)三種狀態。
能夠知道對應簡化數組的一種最優方案裏zsy不會重複走過一條路超過2次。
既然是迴路問題,考慮插頭dp。
\(f[i][j][k]\)表示考慮輪廓線到達\(i\),插頭有\(j\)個,已經用了\(k\)個單插頭的最少代價,
直接轉移便可。code

int n,t[N];ll suft[N],dp[N][3][3],ans;
inline void upd(ll &a,ll b){a=a<b?a:b;}
inline int calc(int x,int r){
  if(r==0)return x;
  if(r==1)return x&1?0:1;
  if(r==2){if(!x)return 2;else return x&1?1:0;}
}
int main()
{
  n=read();for(int i=1;i<=n;i++)t[i]=read();
  for(int i=n;i;i--)suft[i]=suft[i+1]+t[i];ans=suft[1];
  memset(dp,63,sizeof(dp));dp[0][0][0]=0;
  for(int i=0;i<=n;i++)
    for(int a=0;a<3;a++)
      for(int b=0;b<3;b++){
        if(a==0){
          upd(dp[i+1][a][b],dp[i][a][b]+t[i+1]);
          if(b!=2)upd(dp[i+1][a+1][b+1],dp[i][a][b]+calc(t[i+1],1));
          upd(dp[i+1][a+2][b],dp[i][a][b]+calc(t[i+1],2));
        }
        if(a==1){
          if(b!=2)upd(ans,dp[i][a][b]+suft[i+1]);
          upd(dp[i+1][a][b],dp[i][a][b]+calc(t[i+1],1));
          if(b!=2)upd(dp[i+1][a+1][b+1],dp[i][a][b]+calc(t[i+1],2));
        }
        if(a==2){
          upd(ans,dp[i][a][b]+suft[i+1]);
          if(b!=2)upd(dp[i+1][a-1][b+1],dp[i][a][b]+calc(t[i+1],1));
          upd(dp[i+1][a][b],dp[i][a][b]+calc(t[i+1],2));
        }
      }
  printf("%lld\n",ans);
  return 0;
}

E - Odd Subrectangles

考慮給定行後選出列集合的方案數:
若是行的異或和不爲0,那麼總有一半的方案選出來異或和爲1,另外一半爲0,所以方案爲\(2^{m-1}\)
因而答案變成\(2^{m-1}S\),其中\(S\)表示行向量選出來的異或和不爲\(0\)的方案數。
求解選取行向量集合,使其異或和不爲0的方案數是一個經典問題:
考慮求出\(n\)個行向量的線性基,設其大小爲\(r\)
若是僅選取線性基中的元素,顯然沒法使得異或和爲\(0\);
那麼考慮先選取不在線性基中的元素:
對於這樣的一組方案,在線性基中都有惟一的一種選取元素的方案,使得全部元素的異或和爲0.
所以\(S=2^n-2^{n-r}\)class

int n,m,a[N][N],now[N],in[N],p[N][N],r;
inline int poww(int a,int b){
  int res=1;
  for(;b;b>>=1,a=1ll*a*a%mod)
    if(b&1)res=1ll*res*a%mod;
  return res;
}
int main()
{
  n=read();m=read();
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)a[i][j]=read();
  for(int i=1;i<=n;i++){
    memcpy(now,a[i],sizeof(now));
    for(int j=1;j<=m;j++)
      if(now[j]){
    if(in[j])for(int k=j;k<=m;k++)now[k]^=p[j][k];
    else{in[j]=1;memcpy(p[j],now,sizeof(p[j]));r++;break;}
      }
  }
  printf("%lld\n",1ll*(poww(2,n)-poww(2,n-r)+mod)%mod*poww(2,m-1)%mod);
  return 0;
}

F - Pass

考慮直接構造最終序列。由傳球方式能夠知道,第\(i(i\le n)\)個球只會在\(1-i\)我的的手中出現,後\(n\)個求隨意。
所以直接設\(f[i][j]\)dp,最後組合數乘一下便可。sort

char s[N];int n,dp[N][N],c[N][N],ans;
inline void upd(int &a,int b){a+=b;if(a>=mod)a-=mod;}
int main()
{
  scanf("%s",s+1);n=strlen(s+1);
  for(int i=0;i<=n;i++)
    for(int j=c[i][0]=1;j<=i;j++)upd(c[i][j]=c[i-1][j],c[i-1][j-1]);
  dp[0][0]=1;
  for(int i=1;i<=n;i++)
    for(int j=0,c=s[i]-48;j<=i;j++){
      if(j>=c-1)upd(dp[i][j],dp[i-1][j-c+1]);
      if(j>=c)upd(dp[i][j],dp[i-1][j-c]);
    }
  for(int i=0;i<=n;i++)upd(ans,1ll*dp[n][i]*c[n][i]%mod);
  printf("%d\n",ans);
  return 0;
}
相關文章
相關標籤/搜索