Educational Codeforces Round 143
A
题意
两根红蓝方块组成的柱子,可以任意将一根柱子顶端的一个方块移动到另一根柱子顶端,问是否能使得两根柱子均为红蓝交错的颜色。
思路
显然可以转化成一个序列能否从中间分割成两个红蓝交错的序列,也就是判断是否有三个连续的颜色,或者两个颜色连续出现两次以上。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3;
char s1[MAX],s2[MAX];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s%s",s1,s2);
for(int i=m-1,j=n;i>=0;i--,j++)
s1[j]=s2[i];
n+=m;
int len=1,cnt=0;
for(int i=1;i<n;i++)
{
if(s1[i]==s1[i-1])len++;
else len=1;
if(len>2)break;
if(len==2)cnt++;
}
if(len>2||cnt>1)printf("NO\n");
else printf("YES\n");
}
}
B
题意
给一个数轴,然后有若干闭区间,求能否任意移除若干区间,使得覆盖到k点的区间个数 严格大于 覆盖到其他任何一点的区间个数。
思路
可以巧妙思考一下,实际上只有k点恰好同时是一个区间的左端点和一个区间的右端点(可以是同一个左右相等的区间),当且仅当在这种状态下,k能达成题目要求。
证明如下:
充分性容易想到。
使用反证法证明其必要性。
设节点分数为覆盖节点的区间个数,假设k达成题目要求,但不是上述种类的节点,那么有三种情况。
- 如果k没有被任何区间覆盖,那么分数为0,不可能严格大于任何点的分数。
- 如果k仅为某在其左侧区间的右端点,那么左侧任何能给k加分的区间,必定能给k-1点加分。同时,其右侧区间能给k加分的,也一定能给k-1加分(区间左端点会跨过k,至少落在k-1),那么k-1的分数一定大于等于k分数。
- 同理可得如果k仅为某在其右侧区间的左端点,那么k+1的分数一定大于等于k分数。
因此可得矛盾,可以证明其必要性。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,k,l,r;
bool L=0,R=0;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d%d",&l,&r);
if(l==k)L=1;
if(r==k)R=1;
}
if(L&&R)printf("YES\n");
else printf("NO\n");
}
}
C
题意
有n杯茶,每杯ai单位,同时有n个品茶师,每次分别可以喝bi单位的茶。
开始时,茶和品茶师从1-n从左向右依次对应,然后每个人喝掉min(ai,bi)的茶,然后更新ai为被喝后剩余的数量。然后品茶师集体左移一格,i号到i-1号位,最左端的品茶师退出。逐次进行这一过程,直到最后一个品茶师退出。
求每个品茶师总共要和多少单位的茶。
思路
模拟一下可以发现,对于第i杯茶,要被i-n的品茶师喝,可以自然想到前缀数组。
将b求前缀数组,然后可以遍历每一杯茶,二分查找最多可以被多少品茶师喝,然后用差分数组记录一下可供多少人喝,然后还剩下多少,最后统计答案。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int MAX=2e5+5;
ll a[MAX],b[MAX],k[MAX],d[MAX],pre[MAX];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
d[i]=0,k[i]=0;
for(int i=0;i<n;i++)
scanf("%I64d",&a[i]);
for(int i=0;i<n;i++)
scanf("%I64d",&b[i]);
pre[0]=b[0];
for(int i=1;i<n;i++)
pre[i]=pre[i-1]+b[i];
ll bias=0;
for(int i=0;i<n;i++)
{
int pos=upper_bound(pre,pre+n,a[i]+bias)-pre;
k[i]+=1;
k[pos]-=1;
d[pos]+=a[i]+bias-pre[pos-1];
d[pos+1]-=a[i]+bias-pre[pos-1];
bias=pre[i];
}
for(int i=1;i<n;i++)
k[i]+=k[i-1],d[i]+=d[i-1];
for(int i=0;i<n;i++)
{
b[i]=b[i]*k[i]+d[i];
printf("%I64d ",b[i]);
}
printf("\n");
}
}
D
题意
有m,m为偶数个三角形,每条边有权值,每个顶点可以被涂上红色或者蓝色,要求总体必须有相同数量的红色和蓝色。
一种涂色方案的分数为:顶点颜色不同的边的权值之和。
求有多少种方案能够最大化分数,最后取个模。
思路
很明显可以想到,一个三角形只有3R,3B,1R2B,2R1B四种涂色方案(旋转后的认为是一种),如果某个三角形选择3R,3B这种涂色方式,那么就对分数没有贡献,显然不可能使得分数最大化。那么要使得分数最大,就要选择1R2B,2R1B这种涂色方式,然后每个三角形选出最大的两条边,就可以使得分数最大化。
再考虑方案个数,由于有偶数个三角形,并且要求最终R,B数量想等,那么涂色方案应当是1R2B,2R1B各占一半。
再考虑每个三角形内部可能有相等的权值,衍生出不同的选择权值的方案,最后就变成了一个组合问题。
最终答案就是每个三角形内部的方案之积再乘以C^(m/2)_m种方案。
取模用逆元处理一下。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int MOD=998244353;
const int MAX=3e5+5;
ll jc[MAX];
int qpow(int a,int k)
{
int res=1;
for(;k;k>>=1)
{
if(k&1)
res=1ll*res*a%MOD;
a=1ll*a*a%MOD;
}
return res%MOD;
}
int inv(int x){return qpow(x,MOD-2);}
int main()
{
jc[0]=1;
for(int i=1;i<=MAX;i++)
jc[i]=jc[i-1]*i%MOD;
int n,m,a,b,c;
scanf("%d",&n);
m=n/3;
ll res=1;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(a<b)swap(a,b);
if(a<c)swap(a,c);
if(b<c)swap(b,c);
if(a==b&&a==c)res*=3;
else if(a==c||b==c)res*=2;
res%=MOD;
}
res*=jc[n/3];
res%=MOD;
res*=inv(jc[n/3-n/6]);
res%=MOD;
res*=inv(jc[n/6]);
res%=MOD;
printf("%I64d\n",res);
}