ABC399
AtCoder Beginner Contest 399(C~F)
C - Make it Forest
A simple undirected graph F is called a forest if and only if F does not contain any cycle.
用并查集计数即可.
D - Switch Seats
将每个数的两个位置存下来 , 根据条件直接数即可.
用set计数比较好写.
E - Replace
可以转化为一个图论问题 , 要将s中的a转化为t中的b可以看成一条边\(a\rightarrow b\) .
若出度大于1 , 显然无解.
否则若有环 , 如\(a\rightarrow b , b\rightarrow c,c\rightarrow a\) , 3次操作显然不行 , 如果我们先将\(c\rightarrow d\) , 就没有环了 , 可以做到.
但是有可能c没有可以转化的d了 .
我们需要的是在s没出现的一个字母 , 如果所有26个字母都在环内显然就无解 , 否则计算环的数目 .
这里的环不能有其他的边 , 如\(a\rightarrow b , b\rightarrow c,c\rightarrow a,d\rightarrow a\) ,则不需要统计.
最后的答案为除自环外的边数加上纯环的数量.
纯环可以用并查集找到.
void solve() {
  int n;cin>>n;
  string s,t;cin>>s>>t;
  if (s==t) {
    cout<<0<<"\n";
    return ;
  }
  int ans=0;
  for (int i=1;i<=26;++i) fa[i]=i,ok[i]=1;
  for (int i=0;i<n;++i) {
    int x=s[i]-'a'+1,y=t[i]-'a'+1;
    if (to[x] and to[x]!=y) {
      cout<<"-1\n";
      return ;
    }
    if (to[x]) continue;
    merge(x,y);
    to[x]=y;
    in[y]++;
    out[x]++;
    if (x!=y) ans++;
  }
  for (int i=1;i<=26;++i) {
    sz[find(i)]++;
    if (out[i]==1 and in[i]==1) continue;
    ok[find(i)]=0;
  }
  int sum=0;
  for (int i=1;i<=26;++i) {
    if (i==find(i) and ok[i]) {
      sum+=sz[i];
      if (sz[i]>1) ans++;
    }
  }
  if (sum==26) ans=-1;
  cout<<ans<<"\n";
}
F - Range Power Sum
First
求
注意到\(k\)比较小 , 考虑直接展开. 看看能否用前缀和去优化. 一般通过交换求和次序 , 然后将一些项移出和式 , 得到一些能够预处理的东西 , 就可以消除一重和式 .
这样显然可算了. 通过预处理 , 时间复杂度为\(O(NK)\)
需要注意一点 : 在组合数学中 , 我们一般可以认为\(0^0=1\) .
Second
转化一下题目: \(A_i\)表示一个盒子\(i\)里面有\(A_i\)个球
分为两步
1.选择一个区间
2.为这个区间的的球贴\(k\)个标签的方法数
由于k的数据比较小 , 可以考虑dp
dp[i][j][k]枚举到\(i\) , 确定了j 个边界 , 贴了k个标签 的方法数.
对于每一个位置有3种操作
1.什么都不做dp[i+1][j][k]+=dp[i][j][k]
2.设为边界dp[i][j+1][k]+=dp[i][j][k]
3.打上p个标签\(dp[i+1][1][k+p]+=\binom{K-k}{p}A_i^p dp[i][1][k]\)
dp[0][0][0]=1;
  int ans=0;
  for (int i=0;i<=n;++i) {
    for (int k=0;k<=K;++k) {
      for (int j=0;j<=2;++j) {
        dp[i+1][j][k]+=dp[i][j][k],dp[i+1][j][k]%=mod;
        dp[i][j+1][k]+=dp[i][j][k],dp[i][j+1][k]%=mod;
      }
      for (int p=1;p<=K-k;++p) dp[i+1][1][k+p]+=C(K-k,p)*a[i+1][p]%mod*dp[i][1][k]%mod,dp[i+1][1][k+p]%=mod;
    }
  }
  cout<<dp[n][2][K]<<"\n";
由当前位置向后更新会比较好写 , 这样更新不容易出错 , 并且开大数组不用管边界.
Third
想办法减掉一维边界 , 比如先固定一维 , 这里固定右边界
能否快速计算右边的东西呢?
令
看上去似乎可以递推
最后的答案为

                
            
        
浙公网安备 33010602011771号