Educational CF round174(div2)总结
得分总结:场切4道罚时257rank1624
主要问题:
- B题没读懂题吃了罚时。
- A,B题多测都没有清空,各吃一发罚时。
- D题犯唐了,翻转后没有调用,吃四发罚时
简直不是人
更新:2.20 增加F题解
链接:A
我们考虑什么情况下
我们直接判断b的每一位,出现不合法就输出No。
AC记录
ACcode:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 110
// By flyfreemrn
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
ll b[MAXN];
ll n,T,ans;
void work(){
n=read()-2,ans=1;
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++){
b[i]=read();
}
for(int i=1;i<=n;i++){
if(b[i-1]==1&&b[i+1]==1&&b[i]==0){
cout<<"NO\n";
return;
}
}
cout<<"YES\n";
return;
}
int main(){
T=read();
while(T--)work();
return 0;
}
链接:B
首先,题目所给的操作类似于黑白棋盘染色,这提示我们同一种颜色至多两次操作就能全部转化成另一种颜色,第一次选全部在白格上的,第二次选全部在黑格上的,就一定能补缺补漏的转化。
所以,对于每一种颜色,有两种情况。
- 没有相同颜色的格子相接,也就是所有这种颜色的格子都在黑格或白格上,对于这种颜色一次操作就能转化。
- 出现相同颜色的格子相接,我们需要两次操作转化。
因为最后要转化为同一种颜色,所以我们可以去除其中一种颜色的贡献,特判一下 还是 。
AC记录
ACcode:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1010
#define pir pair<ll,ll>
// By flyfreemrn
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
ll addx[4]={0,1,0,-1},addy[4]={1,0,-1,0};
ll n,m,T,sum,res;
ll col[MAXN][MAXN],vis[MAXN][MAXN];
map <ll,ll> t;
set <ll> st;
void work(){
n=read(),m=read();
sum=0,res=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)col[i][j]=read(),st.insert(col[i][j]),t[col[i][j]]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int u=0;u<=3;u++){
ll edx=i+addx[u],edy=j+addy[u];
if(edx>n||edy>m||edx<1||edy<1)continue;
if(col[i][j]==col[edx][edy])t[col[i][j]]=1;
}
}
}
for(auto it=st.begin();it!=st.end();it++){
if(t[(*it)]){
sum+=2,res=2;
}else sum+=1;
}
cout<<sum-res<<endl;
st.clear();
return;
}
int main(){
T=read();
while(T--)work();
return 0;
}
先考虑暴力情况
如果有一个
每找到一个
时间复杂度
优化
我们可以考虑将每一个序列的贡献都记在结尾的
加入一个
那么他对答案的贡献就是
我们发现,这个值是可以递推计算的,我们记上式值为
当我们找到一个
那么每一个
所以我们额外记当前位置
那么
当我们找到一个
当我们找到一个
最后别忘了取模。
AC记录
ACcode:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 998244353
#define MAXN 200010
// By flyfreemrn
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
ll cnt1,cnt2,sum;
ll n,T,ans;
void work(){
n=read(),ans=cnt1=cnt2=sum=0;
for(int i=1;i<=n;i++){
ll a=read();
if(a==1){
cnt1++;
// sum++;
}else if(a==2){
sum=(sum*2+cnt1)%mod;
}else{
ans=(ans+sum)%mod;
}
}
cout<<ans<<endl;
return;
}
int main(){
T=read();
while(T--)work();
return 0;
}
链接:D
回文串的题,我们先记中间位置为
我们可以发现,原串中一些位置与对应的位置是相同的,这些位置不需要调整,而一些位置不相同,这些位置必须被调整。
所以我们找到
接下来,我们分类讨论
- 找不到不对应的位置,原串就是回文的,直接输出
。 到 位置与 到 位置的字母数量完全相同,换句话说 到 是 到 的一个排序,这表示我们只需要调整 到 就可以了。- 除此以外,调整的区间就必须包含
到 和 到 中的一个全部和另一个的一部分
我们先从右往左找,我们枚举区间左端点 让我们可以通过调整 到 使原串回文,再从左往右找,这时候只需要反转一下原串然后重复一遍就可以了。
AC记录
ACcode:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 200010
// By flyfreemrn
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
char c[MAXN],s[MAXN];
ll l,r,n,t[30],T;
ll work(){
// n=read();
for(int i=1;i<=26;i++)t[i]=0;
// cin>>(c+1);
// n=strlen(c+1);
l=n,r=0;
for(ll i=1;i<=n/2;i++){
ll x=(n/2)-i+1,y=(n/2)+i;
if(c[x]==c[y])continue;
l=min(l,i),r=max(r,i);
}
if(l==n&&r==0){
// cout<<"0\n";
return 0;
}
for(int i=l;i<=r;i++){
ll x=(n/2)-i+1,y=(n/2)+i;
ll a=c[x]-'a'+1,b=c[y]-'a'+1;
t[a]--,t[b]++;
}
ll type=0;
for(int i=1;i<=26;i++){
if(t[i])type=1;
}
if(!type){
// cout<<r-l+1<<endl;
return r-l+1;
}
// for(int i=1;i<l;i++){
// ll x=(n/2)-i+1,y=(n/2)+i;
// ll a=c[x]-'a'+1,b=c[y]-'a'+1;
// t[a]++,t[b]++;
// }
for(int i=1;i<=r;i++){
ll x=(n/2)-i+1;
ll a=c[x]-'a'+1;
t[a]+=2;
type=0;
for(int j=1;j<=26;j++){
if(t[j]<0||t[j]%2){
type=1;
}
}
if(!type){
// cout<<i+r<<endl;
return i+r;
}
}
// cout<<2*r<<endl;
return 2*r;
}
int main(){
T=read();
while(T--){
cin>>(s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)c[i]=s[i];
ll ans=work();
for(int i=1;i<=n;i++){
// swap(s[i])
c[i]=s[n-i+1];
}
ans=min(ans,work());
cout<<ans<<endl;
}
return 0;
}
链接:E
逆天分讨,不想写了(
链接:F
我们把题意转化一下,就是在
我们先考虑问题的简化版本。
假如现在只有加边操作,如何计算答案,因为我们要处理无向图的连通性问题,能想到并查集
先处理
接下来我们处理
这样,我们往
同时,因为我们把虚边也存下来了,所以在
正解
对于删边操作,我们可以转化一下,先对操作离线,假如我们在
这就是很显然的线段树分治了,直接套上就能过了。
AC记录
ACcode:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 400010
#define pir pair<ll,ll>
#define dpir pair<pir,ll>
#define ls first
#define rs second
// By flyfreemrn
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
//回溯栈
struct node_modify{
ll pos,fa,siz,type;//0A图 1B图
}t[MAXN*10];
ll id;
//并查集
struct node_dsu{
ll fa[MAXN],siz[MAXN],type;
ll get(ll x){
return fa[x]==x?x:get(fa[x]);
}
void merge(ll x,ll y){//合并
x=get(x),y=get(y);
t[++id]=(node_modify){y,fa[y],siz[y],type};
t[++id]=(node_modify){x,fa[x],siz[x],type};
if(siz[x]>siz[y]){
fa[y]=x;
siz[x]+=siz[y];
}else{
fa[x]=y;
siz[y]+=siz[x];
}
}
void build(ll x){
for(int i=1;i<=x;i++)fa[i]=i,siz[i]=1;
}
}dsu[2];//0加虚边,1只存A图
//线段树分治
struct node_sgt{
ll l[MAXN*4],r[MAXN*4];
ll ans[MAXN];
vector <dpir> vec[MAXN*4];
void build(ll lz,ll rz,ll now){
l[now]=lz,r[now]=rz;
if(lz==rz)return;
ll mid=(lz+rz)>>1;
build(lz,mid,now<<1);
build(mid+1,rz,(now<<1)+1);
}
void insert(ll lz,ll rz,ll now,dpir val){//加边
if(l[now]>=lz&&r[now]<=rz){
vec[now].push_back(val);
return;
}
ll mid=(l[now]+r[now])>>1;
if(lz<=mid)insert(lz,rz,now<<1,val);
if(rz>mid)insert(lz,rz,(now<<1)+1,val);
}
void clear(ll stp){//回溯
while(id>stp){
dsu[t[id].type].fa[t[id].pos]=t[id].fa;
dsu[t[id].type].siz[t[id].pos]=t[id].siz;
id--;
}
}
void work(ll now,ll p){//处理
ll stp=id;
for(int i=0;i<vec[now].size();i++){
ll x=vec[now][i].ls.ls,y=vec[now][i].ls.rs,type=vec[now][i].rs;
if(type==1){
x=dsu[1].get(x),y=dsu[1].get(y);
if(x==y)continue;
if(dsu[0].get(x)!=dsu[0].get(y))p++;
dsu[1].merge(x,y);
}else{
x=dsu[0].get(x),y=dsu[0].get(y);
if(x==y)continue;
ll x1=dsu[1].get(x),y1=dsu[1].get(y);
if(x1==y1)p--;
else dsu[1].merge(x1,y1);
dsu[0].merge(x,y);
}
}
if(l[now]==r[now]){
ans[l[now]]=p;
clear(stp);
return;
}
work(now<<1,p);
work((now<<1)+1,p);
clear(stp);
}
}sgt;
//主函数
ll n,q,idx;
ll st[MAXN],ed[MAXN];
dpir line[MAXN];
map <pir,ll> mp[2];
int main(){
scanf("%lld%lld",&n,&q);
dsu[0].build(n),dsu[0].type=0;
dsu[1].build(n),dsu[1].type=1;
sgt.build(1,q,1);
for(int i=1;i<=q;i++){
char c;
ll x,y;
cin>>c>>x>>y;
ll type=(c=='B'?1:0);
if(mp[type][make_pair(x,y)]){
ll now=mp[type][make_pair(x,y)];
mp[type][make_pair(x,y)]=mp[type][make_pair(y,x)]=0;
ed[now]=i-1;
}else{
mp[type][make_pair(x,y)]=mp[type][make_pair(y,x)]=++idx;
line[idx]=make_pair(make_pair(x,y),type);
st[idx]=i;
}
}
for(int i=1;i<=idx;i++){
if(!ed[i])ed[i]=q;
sgt.insert(st[i],ed[i],1,line[i]);
}
sgt.work(1,0);
for(int i=1;i<=q;i++)cout<<sgt.ans[i]<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!