あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2022.9.24模拟赛解题报告

2022.9.24模拟赛解题报告

T1#

原题

考试的时候没想出来正解,打了个爆搜,拿了60分,爆搜分给的还是挺足的,后来看了题解发现自己是不可能想出正解的。

首先我们在读入数据的时候要处理一下,把当前任务当作一条边,可以完成任务的人为点,用任务将两个点都链接起来,在 a==b 的情况的时候把当前点标记一下必须要做当前的任务,因为这个操作会引起一系列的连锁反应,也就是说当当前点必须去做当前任务时,有的任务可以完成的两个人中包含当前人,那么当前的任务就必须由另一个人做,这样就处理出不能改变的匹配的人和任务,然后我们在进行这个过程当中如果有 paradox 就直接输出 0 就好了,到了后面,直接 BFS 求边点匹配的方案数即可。

Copy
#include<bits/stdc++.h> #define int long long #define P 1000000007 #define N 250010 using namespace std; int n,m,f[N],vis[N],ans=1;//f存放每一个任务被几号做,vis标记当前人是否有任务做,ans存放答案 vector<int>e[N];//存放联通情况 queue<int>q;//队列bfs int bfs(int x)//广搜 { int v=0,o=0;//v累加当前的深度 q.push(x);//当前点入列 vis[x]=1;//标记可以完成 while(!q.empty())//只要队列不空 { int u=q.front();//取出队头元素 q.pop();//弹出 v+=1;//加一 o+=e[u].size();//加上当前点的连边数 for(int i=0;i<e[u].size();i++)//枚举 { int v=e[u][i];//取出终点 if(!vis[v])//如果当前任务没完成 q.push(v),//入列 vis[v]=1;//标记能完成 } } o>>=1;//o乘二 if(v==o)//如果相等的话就是直接乘二即可 return 2; else if(v==o+1) return v; return 0; } signed main() { cin>>n>>m; for(int i=1;i<=n;i++) { int a,b; cin>>a>>b; if(a==b)//相等 { if(vis[a])//如果当前任务已经完成 ans=0;//无解 else q.push(a),vis[a]=1;//否则就放入队列,标记 } else e[a].push_back(b),//否则就建无向图 e[b].push_back(a);//把两个任务链接起来 } while(!q.empty())//只要队列不空 { int u=q.front();//取出队头元素 q.pop();//弹出 for(int i=0;i<e[u].size();i++)//枚举每一个与u相连的边 { int v=e[u][i];//取出终点 if(v==f[u])continue;//如果是父节点就跳过 if(vis[v])//如果当前人必须去完成某个任务 { ans=0;//答案归零 break;//退出 } vis[v]=1;//标记当前点可以被完成 f[v]=u;//标记父亲 q.push(v);//放入队列 } } for(int i=1;i<=m&&ans;i++)//只要答案不是0 if(!vis[i])//当前没有指定的人 ans=ans*bfs(i)%P;//累加答案 cout<<ans<<endl;//输出答案 return 0; }

T2#

T3#

原题

首先应该注意到的是,字符串中,相邻两个字母如果相等,那么相邻的字母可以被删掉而不影响答案
一般人都能想到这个,不过到了这里就容易卡壳,我们不妨换个思路:
考虑 ALO 三个字母的个数,为 a, l, o,由对称性可以假设 a 是最小的,即 a<la<o
那么答案应该是和 A 有关的,我们不妨假设我们要选所有的 A,尝试构造一个解
那么接下来我们要做的其实是把 LO 删掉,如果想要不改变 A 的数量,如何删掉 LO
有两种方法:
方法一、删去类似 LOLOLOLOL 串中的 LO,那么 LO 的数量同时降低
方法二、删去类似 LOLOLOLOL 串中的单边的 L 或者 O,那么单边的数量降低
我们发现无法删掉的 LO 都是“单个”的,即 ALAOLO
如果想删掉这些单个字母,就只能删掉一个 A
那么……算法的流程大概是这样:
判断:能否只通过方法一和方法二构出答案?
可以 > 输出当前 A 的数量乘以 3
不可以 > 说明通过方法一和方法二之后,LO 的数量依旧不平衡
那么只能考虑删掉 A

Copy
#include<bits/stdc++.h> using namespace std; char s[2000010],v[2000010]; int tot,a,l,o,ul,uo; int main() { char A,L,O;//存放字符 scanf("%s",s);//输入原字符串 int len=strlen(s);//测出字符串的长度 for(int i=0;i<len;i++)//遍历每一个字符 if(s[i]!=s[i-1])//如果当前的字母和上一个字母是不一样的 v[tot++]=s[i];//存入v数组 int flag=0;//flag用于标记 for(int i=0;i<tot;i++)//遍历统计每一个字母的数量 if(v[i]=='A')a++; else if(v[i]=='L')l++; else if(v[i]=='O')o++; if(a<=l&&a<=o)//A最少 A='A',L='L',O='O'; else if(l<=a&&l<=o)//l最少 A='L',L='A',O='O'; else A='O',L='L',O='A';//o最少 a=l=o=0;//清空 for(int i=0;i<tot;i++)//遍历每一个字符 { if(v[i]==A)//如果当前的字母等于当前最少的字母 flag=0,a++;//重置flag,a的数量加一 else//否则 { if(v[i]==L&&(flag&1)==0)//如果当前点是L并且flag&1的结果是0 { l++;//l数量加一 if(i==0&&v[i+1]==A)ul++;//如果当前点是第一个并且下一个就是A就ul加一 else if(i==tot-1&&v[i-1]==A)ul++;//如果当前点是最后一个并且上一个就是A就ul加一 else if(v[i-1]==A&&v[i+1]==A)ul++;//如果当前点的前后都是A的话就ul加一 flag|=1;//flag进行或运算 } if(v[i]==O&&(flag&2)==0)//如果当前点是O并且flag&2的结果是0 { o++;//o数量加一 if(i==0&&v[i+1]==A)uo++;//如果当前点是第一个并且下一个就是A就uo加一 else if(i==tot-1&&v[i-1]==A)uo++;//如果当前点是最后一个并且下一个就是A就uo加一 else if(v[i-1]==A&&v[i+1]==A)uo++;//如果当前点的前后都是A的话就uo加一 flag|=2;//进行异或运算 } } // cout<<flag<<endl; } if(uo>l)a-=uo-l;//如果当前的uo大于l的话就只能减少a if(ul>o)a-=ul-o;//同理 cout<<a*3<<endl;//输出 return 0;//好习惯 }
posted @   北烛青澜  阅读(17)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
目录