这次周赛有三道题:模拟,找规律,拓扑排序
acwing 3694.A还是B
链接:https://www.acwing.com/problem/content/3697/
题目描述
解题思路
遍历字符串,求出A在字符串里出现了cnt次,那么B就出现了n-cnt次
如果cnt>n-cnt,输出A 如果cnt<n-cnt,输出B 如果cnt==n-cnt,输出T
注意事项
读入字符串时不能这么写,因为scanf会读入回车符
while(m--){
char x;
scanf("%c",&x);
}
要这么写
while(m--){
char x;
scanf(" %c",&x);
}
或者一整行读入也可以
结束,代码很简单就不贴代码了
acwing 3695.扩充序列
链接:https://www.acwing.com/problem/content/description/3698/
题目描述
解题思路
看到k的值这么大,数列又这么有规律,就应该知道这是道数学找规律题
当k=4时
下标:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
数列:1 2 1 3 1 2 1 4 1 2 1 3 1 2 1
首先我们能发现,当下标为2^p时,数列里对应的数就是p+1; 下标为奇数时,数列里对应的就是1
对于其他数,我们找几个特殊值
a[6=2 * 3]=2;
a[12=2 *2 *3]=3;
a[14=2 * 7]=2;
不难看出,a[x]=x分解质因数后2的个数+1
所以我们直接将n分解质因数后输出个数+1就行了
结束,代码很简单就不贴代码了
acwing 3696. 构造有向无环图
链接:https://www.acwing.com/problem/content/description/3699/
题目描述
解题思路
先讲下判环思路
一个有向图,记录下每个节点i的入度cnt[i],每次寻找入度为0的点,将其push进队列作为起点来遍历图,遍历一条边就–cnt[i],直到没有入度为0的点
不难发现,如果图有环,环上的点入度永远不会被更新为0
所以用一个sum记录遍历到的节点的次数,每次遍历到一个起点都++sum,如果整张图遍历结束后,
sum!=n,说明有环
代码思路
首先想清楚一件事,如果一张图给定的有向边没有组成环,那总有一种方法使无向边也不组成环
例如:一张图的有向边组成了1->2->3,无向边是(1,3),那变成有向边就是(1,3)
再比方说有向边是1->2->3->4->5,无向边是(2,4),那变成有向边就是(2,4)
总结一下,只有无向边连接着一条链时,才有可能组成一个环;而我们只用将无向边的方向变为 前面的点->后面的点就不会成环
所以我们直接用链式前向星存图,将无向边存为两条有向边,从入度为0的点开始遍历,将这个点的全部边都遍历一遍记录进ans数组,这样无向边的方向就会被确定且方向由前向后
结束,上代码
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
const int N=200010,M=400010;
typedef pair<int,int> PII;
struct Node{
int op,y,nxt;
}e[M];
int n,m;
int head[N],idx;
int cnt[N];//入度
bool vis[N];
vector<PII> ans;
void add(int op,int x,int to)
{
e[++idx].y=to;
e[idx].op=op;//记录边是有向/无向
e[idx].nxt=head[x];
head[x]=idx;//链式前向星存图
if(op) cnt[to]++;//只有有向边计入入度
}
bool bfs(){
queue<int> q;
int sum=0;
for(int i=1;i<=n;i++){
if(!cnt[i]) q.push(i);//寻找入度为0的点作为起点
}
while(!q.empty()){
int x=q.front();q.pop();
vis[x]=1;
sum++;
for(int i=head[x];i!=-1;i=e[i].nxt){
int to=e[i].y;
if(vis[to]) continue;
ans.push_back(make_pair(x,to));
if(e[i].op) cnt[to]--;//去掉这条有向边,to的入度--
if(e[i].op&&!cnt[to]) q.push(to);//寻找入度为0的点 将其作为下一个起点
}
}
return sum==n;//如果有点没被遍历到,说明有环,return false
}
int main(){
int T;
scanf("%d",&T);
while(T--){
ans.clear();
idx=0;//初始化
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
cnt[i]=0;vis[i]=0;head[i]=-1;//初始化 用memset常数太大会超时
}
for(int i=1;i<=m;i++){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
add(op,x,y);
if(!op) add(op,y,x);
}
if(!bfs()){
puts("NO");
continue;
}
puts("YES");
for(int i=0;i<ans.size();i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
}
return 0;
}