牛客周赛140做题报告
A 小红的区间计数
知识点:签到
思路:判断一下区间是不是包含这几个点就行了
B 小红的牛魔
知识点:模拟
思路:很经典的类括号序列问题,\(u 和 o\) 入栈的时候判断一下就行了
C 小红的矩阵计数
知识点:模拟
思路:对所有 \(L\) 进行判断就行了,判断方法有很多种,这里只给出一种
Code
点击查看代码
bool check(char c1,char c2,char c3)
{
int o1=0,o2=0,o0=0;
if(c1=='1')
{
o1++;
}
if(c1=='2')
{
o2++;
}
if(c1=='0')
{
o0++;
}
if(c2=='1')
{
o1++;
}
if(c2=='2')
{
o2++;
}
if(c2=='0')
{
o0++;
}
if(c3=='1')
{
o1++;
}
if(c3=='2')
{
o2++;
}
if(c3=='0')
{
o0++;
}
if(o1==1&&o0==1&&o2==1)
{
return 1;
}
return 0;
}
char a[1004][1004];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
int ans=0;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char c1=a[i][j];
char c2=a[i-1][j];
if(j-1>=1)
{
if(c1!=c2&&c2!=a[i][j-1]&&c1!=a[i][j-1]&&check(c1,c2,a[i][j-1]))
{
ans++;
}
if(c1!=c2&&c2!=a[i-1][j-1]&&c1!=a[i-1][j-1]&&check(c1,c2,a[i-1][j-1]))
{
ans++;
}
}
if(j+1<=m)
{
if(c1!=c2&&c2!=a[i][j+1]&&c1!=a[i][j+1]&&check(c1,c2,a[i][j+1]))
{
ans++;
}
if(c1!=c2&&c2!=a[i-1][j+1]&&c1!=a[i-1][j+1]&&check(c1,c2,a[i-1][j+1]))
{
ans++;
}
}
}
}
cout<<ans<<endl;
}
D E 小红的排序
知识点:DSU(并查集)
思路:遍历数组,对于每一个下标 \(i\) 来说,若不越界,都有 \(i+x\) 和 \(i+y\) 可以直接到达,遍历完成后,一些下标会形成若干个连通块,用并查集维护,最后对于每一个 \(i\) 和 \(a[i]\) 都应该在一个连通块里
Code
点击查看代码
void solve()
{
cin>>n>>x>>y;
vi p(n+1);
for(int i=1;i<=n;i++)
{
cin>>p[i];
}
for(int i=1;i<=n;i++)
{
int d=abs(i-p[i]);
if(d%gcd(x,y)==0||d%x==0||d%y==0)
{
continue;
}
else
{
cout<<"No"<<endl;
return;
}
}
cout<<"Yes"<<endl;
}
注:赛时做的时候用的是裴蜀定理,想的是用 gcd(x,y)到达能到达的点
F 小红的三角形构造
知识点:trick
思路:无思路,纯典,
对于一个奇数来说,他作为一个直角边,
另外的直角边是 $\frac{n^2-1}{2} $,斜边是 $\frac{n^2+1}{2} $
对于一个偶数来说,他作为一个直角边,
另外的直角边是 \({(\frac{n}{2})}^2-1\),斜边是$ {(\frac{n}{2})}^2+1 $
Code
点击查看代码
void solve()
{
cin>>x;
if(x<3)
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
if(x&1)
{
cout<<x<<' ';
cout<<(x*x-1)/2<<' '<<(x*x+1)/2<<endl;
}
else
{
cout<<x<<' ';
cout<<(x*x/4)-1<<' '<<(x*x/4)+1<<endl;
}
}
}
G 小红的生成树构造
知识点:DSU(并查集),最小生成树(kruskal)
思路:将边存到边集中,对于两条边分别是 \(A,B\) 或者 \(C,D\),权值为0,其他边权值为1,我们首先要排除某个点连不到与其对应的那个点的情况,将权值为0的点并到并查集里,对于每一个连通块来说,都应该有 \(A,B\) 或者 \(C,D\) 两种,如果没有两种,就不满足条件,剩下的情况全为合法情况,答案也很显然,对边集按权值进行排序,跑一遍kruskal就行了,这样最后的生成树应该是左边为 \(AB\) 树,右边为 \(CD\)
树,用一条边把他们连起来即可
Code
点击查看代码
struct node{
int u,v,w;
};
bool cmp(node a,node b)
{
return a.w<b.w;
}
void solve()
{
cin>>n>>m;
init();
cin>>s;
s='5'+s;
vector<node> a;
while(m--)
{
int u,v;
cin>>u>>v;
if(s[u]==s[v]
||(s[u]=='A'&&s[v]=='B')
||(s[u]=='B'&&s[v]=='A')
||(s[u]=='C'&&s[v]=='D')
||(s[u]=='D'&&s[v]=='C'))
{
a.pb({u,v,0});
}
else
{
a.pb({u,v,1});
}
}
for(auto [u,v,w]:a)
{
if(!same(u,v)&&w==0)
{
join(u,v);
}
}
vi via(n+1);
vi vib(n+1);
vi vic(n+1);
vi vid(n+1);
for(int i=1;i<=n;i++)
{
int root=find(i);
if(s[i]=='A')via[root]=1;
if(s[i]=='B')vib[root]=1;
if(s[i]=='C')vic[root]=1;
if(s[i]=='D')vid[root]=1;
}
for(int i=1;i<=n;i++)
{
int root=find(i);
if (s[i] == 'A' || s[i] == 'B')
{
if (!via[root] || !vib[root])
{
cout << "No" << endl;
return;
}
}
else
{
if (!vic[root] || !vid[root])
{
cout << "No" << endl;
return;
}
}
}
init();
cout<<"Yes"<<endl;
sort(all(a),cmp);
for(auto [u,v,w]:a)
{
if(!same(u,v))
{
join(u,v);
cout<<u<<' '<<v<<endl;
}
}
}

浙公网安备 33010602011771号