ABC263

ABC263

img

tasks

VP

score A B C D E F G
105:02 0:24 4:11 15:03 38:49 85:02
+4 +1 +1 +2

rk:316th
perf:2012

A、B

忽略。

C

就是记一下 next_permutation 这个函数。
或者爆搜也行。

code
void work(){
  cin>>n>>m;vi f;
  L(i,1,n) f.pb(0);
  L(i,1,m-n) f.pb(1);
  do{
    L(i,0,m-1) i(!f[i]) 
      cout<<i+1<<" ";
    cout<<'\n';
  }while(next_permutation(all(f)));
}

D

稍微分类讨论一下,把问题转化成更为更加可解的情况。

  • 如果整个数组 a 都被覆盖

此时答案显然是 min(L,R)n

  • 如果数组不是完全覆盖

中间必然有一段 [l,r] 没有被改变。
考虑一个前缀和数组 si=j=1iaj,此时的答案为 srsl1+R×(nr)+L×(l1)

所以枚举左端点 l 和后缀最小和 sl+R×(nr) 并更新答案即可。

code
void work(){
  cin>>n>>x>>y;
  L(i,1,n) cin>>a[i],s[i]=a[i]+s[i-1];
  R(i,n,0){
    sum=min(sum,s[i]+y*(n-i));
    ans=min(ans,x*i-s[i]+sum);
  }cout<<ans;
}

E

期望 DP,倒推。
fi 表示在位置 i 时的期望投掷次数。
对于 DP 的初始状态,显然有 fn=0
当前转移到的 fi,可以推得状态转移方程:fi=1+1Aij=ii+Aifj
但是这样转移的过程中会产生自环,因为等式左右两边都有 fi 这一项。
所以移项消掉右边的 fi,得到:fi=Ai+1+j=i+1i+AifjAi
那个 的部分显然可以用后缀和优化转移,这样就解决了。

时间复杂度:O(nlog2mod)

code
void work(){
  cin>>n;vector<Z>a(n*2,0),f(n*2,0),s(n*2,0);
  L(i,1,n-1) cin>>a[i];f[n]=0;
  R(i,n-1,1){
    Z res=s[i+1]-s[i+1+a[i].val()];
    f[i]=(a[i]+1+res)/a[i];s[i]=s[i+1]+f[i];
  }cout<<f[1];
}//取模结构体Z可以翻我的缺省源

F

题目相当于给出了一棵 n+1 层的满二叉树。
最底下一层刚好对应 1,2,2n 的人。
从最上层开始向下转移。
枚举所有左右子树胜利的情况,取其中 max 值即可。
同时记录当前状态下的连胜场次数,遍历到最底层时直接返回贡献即可。
显然可以记忆化搜索。
时间复杂度:O(n2n)

code
const int N=(1<<17)+100,INF=1e9;
int n,c[N][20],f[N][20];
int dfs(int p,int w){
  if(p>=(1<<n)) return c[p^(1<<n)][w];if(~f[p][w]) return f[p][w];
  return f[p][w]=max(dfs(lc,w+1)+dfs(rc,0),dfs(lc,0)+dfs(rc,w+1));
}void work(){
  cin>>n;L(i,0,((1<<n)-1)) L(j,1,n) cin>>c[i][j];
  me(f,-1);cout<<dfs(1,0);
}

G

蒟蒻只会网络流做法。
本题的网络流建模方法其实不止一种,这里会提到两种。

建模一

考虑拆点,每个 ai 对应的点 i 拆成入点 i 和出点 i+n,分别向源点和汇点连容量为 bi 的边。
枚举所有组合情况,如果满足和为质数,其入点向出点连边即可。
最后结果除二就是答案。

code
void work(){
  cin>>n;vi a(n),b(n);
  F.st=n*2+1,F.ed=n*2+2;
  es(10000000);
  L(i,0,n-1){
    cin>>a[i]>>b[i];
    F.I(F.st,i,b[i]);
    F.I(i+n,F.ed,b[i]);
  }L(i,0,n-1) L(j,0,n-1) 
    if(f[a[i]+a[j]]) F.I(i,j+n,INF);
  cout<<F.dinic()/2;
}

建模二

赛时做法,无比愚蠢。
先忽略 1,不拆点,按上面的方法建图。
得到最大流之后引入新的汇点,把之前的汇点和 1 连上去。
再次跑出最大流,加上剩余的除二即可。
但确实愚蠢了不少。

code
void work(){
  cin>>n;vi a(n),b(n);
  L(i,0,n-1){
    cin>>a[i]>>b[i];
    if(a[i]==1) c1=b[i],b[i]=0;
  }m=*max_element(all(a))*2;
  es(10000000);
  L(i,0,n-1)
    if(a[i]&1) F.I(i,n+1,b[i]);
    else{
      F.I(n,i,b[i]);
      L(j,0,n-1) if((a[j]&1)&&f[a[i]+a[j]])
        F.I(i,j,INF);
    }
  F.st=n,F.ed=n+1;a1=F.dinic();
  F.I(n+2,n+1,c1);L(i,0,n-1) 
    if(a[i]%2==0&&f[a[i]+1]) F.I(i,n+2,INF);
  a2=a1+F.dinic();
  ans=a2+(c1-(a2-a1))/2;
  cout<<ans;
}

Ex

二分+计算几何?

img

posted @   AIskeleton  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示