回归回归,终于考完了,暑假加训开始了!!!集训开始了!!!
今天还把Typora的主题给搞了个自己喜欢的,同时加入了我校ACM集训队,虽然比较弱,但是还是有区域银牌实力的!训练氛围比我之前那个sb工作室好多了。
关于我怎么加入的,很简单,老师看我愿意坚持训练就让我加入了,对,就是这么简单。然后,关于我校集训队计划,暂时没有动静,电子科大都已经快完成了暑假前集训的选拔了
没办法,咱们弱校没得比,也不知道集训计划怎么样的,还是就是自己玩?
好了好了,上正文,今天的补题,直接Typora复制的,也别嫌我懒,cf版刷阶段题意也没写直接标记了思路代码结束了
6.19 解题报告
前排提醒,务必自己再做一遍
abcDEF
D
题意
01串翻转操作,变成至多1个连续1段的最小操作数
思路
枚举答案串,推式子,前后缀预处理,后缀化简
特判:答案串全是0,cost=n-pre[n]
令pre[i]:表示前缀0的数量
枚举这段连续段的[l,r]段,尝试这个序列变成000[1111]000的最小操作数
钦定$[l,r]$区间为答案的连续1段,则cost=左变0+中变1+右变0,左=l-1-pre[l-1],中=pre[r]-pre[l-1],右=(n-r)-(pre[n]-pre[r])
l:l-1-2*pre[l-1], r:n-r-pre[n]+2*pre[r],ans=min(A[l]+B[r]),处理后缀mn[i]即可优化r的枚举,枚举l就是答案了
倒序枚举可以省掉A和B数组
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
char s[MAXN];
int t,n,sum[MAXN];
int main(){
for(scanf("%d",&t);t;t--){
scanf("%d",&n);scanf("%s",s+1);
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+1-(s[i]-'0');
int ans=n-sum[n],mn=n;
for(int i=n;i;--i){
mn=min(mn,n-i-sum[n]+2*sum[i]);
ans=min(ans,mn+i-1-2*sum[i-1]);
}
printf("%d\n",ans);
}
return 0;
}
E
题意
从1节点到n节点最小或路径和
思路
贪心构造+并查集
按位贪心,从高位到低位,看看每一位能否是0,并查集判断连通性,就说明能够全0走到否则就必须是1
如何判断每一位可以为0?
当前构造答案为ans=010110110
判断每一位时,i位到最高位确定,后面所有位任选,即w|X!=X -> 不能选这条边,反之可以选,选择所有边之后,判断1和n是否在连通块中即可
代码
/*
高位到低位的贪心,看看这个bit位能不能保持0到达终点n?
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int n,m;
struct DSU {
vector<int> p, sz;
DSU(int n = 0){init(n);}
void init(int n){p.resize(n+1); sz.assign(n+1,1); iota(p.begin(),p.end(),0);}
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
bool unite(int a,int b){a=find(a); b=find(b); if(a==b) return false; if(sz[a]<sz[b]) swap(a,b); p[b]=a; sz[a]+=sz[b]; return true;}
}dsu;
struct EDGE{
int u,v,w;
}e[MAXN];
bool check(int ans,int X){
dsu.init(n);
for(int i=1;i<=m;++i){
if((e[i].w|X)==X)dsu.unite(e[i].u,e[i].v);
}
return dsu.find(1)==dsu.find(n);
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;++i)cin>>e[i].u>>e[i].v>>e[i].w;
int ans=0;
for(int i=31;i>=0;i--){
if(!check(ans,ans|((1<<i)-1)))ans|=(1<<i);
}
cout<<ans<<'\n';
return 0;
}
F线段树不会写呜呜呜
F
题意
一个排列作为高度,从任意i位置开始跳到j位置,j位置限制{$Hj \le Hi-D,|i-j|\le R$}最多能跳多少次?
思路
扫描线+线段树优化dp
dp[i]:表示第i个位置开始跳能跳多少次
转移dp[i]=max(dp[j] for all j in (i-R,i+R))+1
发现查找的其实是一个区间,所以可以用线段树优化,就是区间最大值o(n)-> o(logn)
第二维限制:扫描线
符合条件的可跳Hj具有单调性,枚举高度H // (不断更新可转移位置,然后DP)
边加入线段树,边查询即可,加入的时候加入了当前高度可以跳到的高度位置j,在线段树中区间查[i-R,i+R]的max(dp[j])即可
线段树:建树下标,存储信息:可选位置j,DP[j]
代码
//只需要一个支持单点修改的线段树,然后在值域区间上枚举加入线段树就行
CF板刷
2033C
双指针+真交换
/*
1.交换的两个位置天然指定可以使用双指针 -> 避免了交换后产生的影响,单独考虑直接不用管了
2.如果两个位置向后相等,考虑交换,最后一遍统计
3.交换操作是真交换
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int num[MAXN],n;
int main(){
int T;
for(cin>>T;T;T--){
cin>>n;for(int i=1;i<=n;++i)cin>>num[i];
for(int i=1,j=n;i<=n/2;++i,j--){
if(num[i-1]==num[i]||num[j]==num[j+1])swap(num[i],num[j]);
}
int cnt=0;
for(int i=1;i<n;++i)if(num[i]==num[i+1])cnt++;
cout<<cnt<<'\n';
}
return 0;
}
2033E
讲到过,排列成圈问题
这个题目就是最后共有m个圈,每个圈的花费cost=ceil((size-2)/2)
出错点:板子写错了WWW,换了个板子A了
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int num[MAXN],id[MAXN],n;
struct DSU {
vector<int> p, sz;
DSU(int n = 0){init(n);}
void init(int n){p.resize(n+1); sz.assign(n+1,1); iota(p.begin(),p.end(),0);}
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
bool merge(int a,int b){a=find(a); b=find(b); if(a==b) return false; if(sz[a]<sz[b]) swap(a,b); p[b]=a; sz[a]+=sz[b]; return true;}
int getsz(int x){return sz[p[x]];}
};
int main(){
int T;
for(cin>>T;T;T--){
memset(num,0,sizeof num);
cin>>n;for(int i=1;i<=n;++i)cin>>num[i];
int ans=0;DSU dsu(n);
for(int i=1;i<=n;++i)
{
if(num[i]==i)continue;
if(!dsu.merge(i,num[i]))ans+=(dsu.getsz(num[i])-1)/2;
}
cout<<ans<<'\n';
}
return 0;
}
2028B
数学推式子,分类讨论
发现是等差数列,
就是找最大的k使得,$b*(k-1)+c\le n$,
原来的等差变成mex数组,最后变成的肯定是[0...n-1]的情形
这样等差数组的上限就变成了n了,所得的排列也是k项就结束了
代码:
/*
题意:a数组是等差数列,每次最大值转化为mex
1 3 5 7 9 11 13 15 17 19 21
b*(k-1)+c<=n,最大的k满足
*/
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
int T;
for(cin>>T;T;T--){
ll n,b,c;cin>>n>>b>>c;
if(c>=n)cout<<n<<'\n';
else{
if(b)cout<<n-(n-c-1)/b-1<<'\n';
else{
if(n-c>=3)cout<<-1<<'\n';
else cout<<n-1<<'\n';
}
}
}
return 0;
}

浙公网安备 33010602011771号