Codeforces Round #782 (Div. 2)

Codeforces Round #782 (Div. 2)

A

1000

CF1659A Red Versus Blue

有一个长度为 n 的字符串由 r 个字符 Rb 个字符 B 组成,要求其中连续相同的字串长度最小。
n100,1b<r,b+r=n

考虑小学数学中的植树问题,将字符 B 插入 R 之间,把 R 分成 b+1 段。
每段 R 的长度为 xy+1,剩余的间隔插入即可。

时间复杂度: O(n)

#define L(i,j,k) for(int i=(j);i<=(k);i++)
int n,x,y;
void work(){
  cin>>n>>x>>y;
  int t1=x/(y+1);
  int t2=x%(y+1);
  L(i,1,y){
    L(j,1,t1) cout<<'R';
    if(i<=t2) cout<<'R';
    cout<<'B';
  }L(i,1,t1) cout<<'R';
  cout<<'\n';
}

B

1300

CF1659B Bit Flipping

给定 01 串,每次操作翻转整个序列除某一指定元素,求 k 次操作后使字典序最大的结果并输出方案。
n2105

考虑贪心,从低位向高位枚举,分配最少使当前位为 1 的操作次数即可。

举个例子:如果当前位初始为 1,操作数 k 为奇数,就需要有一次指定当前位不翻转餐能保证最终的值为 1
最后特判一下最后一位要用完所有剩余操作次数的情况。

时间复杂度: O(n)

#define L(i,j,k) for(int i=(j);i<=(k);i++)
int n,k;
const int N=2e5+10;
char s[N],o[N];int a[N];
void work(){
  cin>>n>>k>>(s+1);
  int x=k;
  L(i,1,n) a[i]=0;
  L(i,1,n){
    if(s[i]=='1'){
      if((k&1)&&x) a[i]=1,x--,o[i]='1';
      else if(!(k&1)) o[i]='1';else o[i]='0';
    }else{
      if(!(k&1)&&x) a[i]=1,x--,o[i]='1';
      else if((k&1)) o[i]='1';else o[i]='0';
    }
  }if(x) a[n]+=x;
    if(a[n]%2==k%2) o[n]=s[n];
    else o[n]=(s[n]=='0'?'1':'0');
  L(i,1,n) cout<<o[i];cout<<'\n';
  L(i,1,n) cout<<a[i]<<" \n"[i==n];
}

朴素思想引出正解

C

1500

CF1659C Line Empire

n 个城市,位置分别为 ai,可以把任何占领的城市作为首都,初始首都位置为 0
每次可以选择花费 |aip|×x 将首都移动到城市 i。(p 为当前首都位置)
每次可以选择花费 |aip|×y 攻占城市 i。求攻占所有城市的最小花费。

n2105,ai109

还是贪心思路。
如果转移首都可以使答案更优就转移。
假设当前首都在编号为 i 的城市。
如果将首都转移到 i+1,消耗 dis(i,i+1)×y
如果不转移首都,则之后相当于转移要多消耗 dis(i,i+1)×(ni1)
比较两者的值确定决策即可。

时间复杂度: O(n)

#define L(i,j,k) for(int i=(j);i<=(k);i++)
int n,a,b;
const int N=2e5+10;
int x[N],s[N];
int dis(int a,int b){return x[b]-x[a];}
void work(){
  cin>>n>>b>>a;int ans=0,c=0;
  L(i,1,n) cin>>x[i];
  L(i,1,n){
    ans+=dis(c,i)*a;
    if((n-i)*a*dis(c,i)>dis(c,i)*b)
      ans+=dis(c,i)*b,c=i;
  }cout<<ans<<'\n';
}

D

1900

CF1659D Reverse Sort Sum

有 01 序列 A,进行 n 次操作,第 i 次将前 i 位排序,每次操作得到的序列相加得到序列 C
已知序列 C,求序列 A
n2105

首先很容易想到,s=i=1ncin 就是序列 A1 的个数。
从后向前考虑,Cn 的值只能是 n0 (原因不难想到)
由此很容易知道 An 的值。
将其拓展到当前第 i 位的情况:如果 Ci=i,则 Ai=1,否则为 0
考虑如何向前递推:
因为已知第 i 为以及之后的情况,同时已知 s 的值,我们可以推算出之前区间 1 的个数。
考虑消除第 i 次操作产生的影响,假设有 k1,回退操作相当于对 [ik+1,i] 区间内的 Ci 减去 1
这个可以用树状数组维护实现,每次单点修改 ik+1 位置上的值,将其减一,之后对于当前的 Ci,就能通过原先的 Ci 加上树状数组 [1,i] 的前缀和实现。即 Ci=Ci+ask(i)
时间复杂度:O(nlog2n)

#define L(i,j,k) for(int i=(j);i<=(k);i++)
int n,s;
const int N=2e5+10;
int a[N],c[N];
void change(int x,int k){for(;x<=n;x+=lb(x))a[x]+=k;}
int ask(int x){int s=0;for(;x;x-=lb(x))s+=a[x];return s;}
void work(){
  cin>>n;L(i,1,n) cin>>c[i];
  L(i,1,n) s+=c[i];s/=n;
  me(a,0);R(i,n,1){
    b[i]=(c[i]+ask(i)==i);
    change(i-s+1,-1);s-=b[i];
  }L(i,1,n) cout<<b[i]<<" \n"[i==n];
}

其实好像还有一种从前往后考虑的做法,在 CF 讨论区。

E

2200

CF1659E AND-MEX Walk

给定 n 个点,m 条边的带权无向联通图。
q 次询问,每次询问给定两个点 u,v,确定某条路径,使 MEX{w1,w1&w2,,w1&w2&&wk} 最小,求最小值。
n,m105,wi<109

首先观察样例,可以猜想是否答案只能是 0,1,2 中某数,即答案不大于 2

证明如下:
设某条路径上的权值组成数组 M
运用反证法,假设答案大于 2,则在 M 中同时出现 1,2
由于与运算具有不升性,如果当前假设成立,则存在 Mi&2=1,与基本事实不符。
Q.E.D

因为答案只有 3 种,只要排除了某两种可能,就可以确定答案。

  • 答案为 0 的情况:

判断从 uv 的路径中,是否存在二进制下某一位使得 W 中所有数在这一位上都是 1
考虑对于二进制下每一位开一个并查集维护,如果 u,v 某一位上处于同一个连通块,则答案为 0

  • 答案为 1 的情况:

可以想到答案为 1 必须满足一个性质:路径上存在一个点 r,使得 ir,Wi>1andWr+1=0
即只要到达那个地方保证在到终点前经过一个使得与之和等于 0的点,接下来就与路径无关了。

所以,我们枚举不是最低位的每一位,找到有可能存在边 (u,v,w) 使得 w&2k,w&1 均为 0

这就要用到之前的并查集,同时对于每个点,记录经过这个点的所有边的边权与和 fi
将同一个连通块内的所有点的 f 值取与和。如果与和为 0 则说明这个连通块内的点能使得答案为 1

时间复杂度:O(30nα(n))

#define L(i,j,k) for(int i=(j);i<=(k);i++)
int n,m,q;
const int N=1e5+100,lim=(1<<30)-1;
int z[N],x[N];bool t[N];
struct DSU{
  int f[N];void cl(){L(i,1,n) f[i]=i;}
  int cz(int x){return x==f[x]?x:f[x]=cz(f[x]);}
  void hb(int x,int y){x=cz(x),y=cz(y);f[x]=y;}
  bool ch(int x,int y){return cz(x)==cz(y);}
}s[35];
void solve(){
  int l,r;cin>>l>>r;
  L(i,0,29) if(s[i].ch(l,r))
    return cout<<0<<'\n',void();
  cout<<(t[l]?1:2)<<'\n';
}void work(){
  cin>>n>>m;L(i,1,n) z[i]=lim;
  L(i,0,30) s[i].cl();
  L(i,1,m){
    int u,v,w;cin>>u>>v>>w;
    z[u]&=w,z[v]&=w;
    L(j,0,29) if(w&(1<<j))
      s[j].hb(u,v);
  }L(i,1,29){
    L(j,1,n) x[j]=lim;
    L(j,1,n) x[s[i].cz(j)]&=z[j];
    L(j,1,n) t[j]|=(!(x[s[i].cz(j)]));
  }cin>>q;L(i,1,q) solve();
}

大胆猜想,小心证明

posted @   AIskeleton  阅读(32)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示