Educational Codeforces Round 143 (Rated for Div. 2)

A

Two Towers

题意:有两座高分别为n,m的塔,塔是由多个高为1的红/蓝方块搭成。告诉你两座塔的颜色组成,问能否可以经过若干次操作使两座塔都没有相邻块颜色相同。每次操作,可以把其中一座塔顶移到另一座塔上。

思路:我们可以把A串和B串反向连接起来,只要相邻方块颜色相同的次数不超过1,就是YES,否则No。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
string A,B;
int n,m;
void solve()
{
	cin>>n>>m;
	cin>>A>>B;
	reverse(A.begin(),A.end());
	B+=A;
	int cnt=0;
	for(int i=0;i<B.length()-1;i++)
	{
		if(B[i]==B[i+1]) cnt++;
	}
	if(cnt<=1) puts("YES");
	else puts("NO");
}
signed main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	// ios;
	int _t=1;
	cin>>_t;
	while(_t--) solve();
	system("pause");
	return 0;
}

B

Ideal Point

题意:给定n条线段(从l到r),定义f(x)为覆盖点x的区间个数。给定k,问能否通过删除若干区间的方式,使k满足对于任意x,f(k)>f(x)。

思路:差分统计覆盖次数,把f(x)>=f(k)的点存起来。若要是删除区间,则一定是删除覆盖x,不覆盖k的区间。我们对于每个x,统计这样的区间个数,比较区间个数与f(x)-f(k)的大小关系。若所有点的区间个数都大于f(x)-f(k),则yes

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n,k;
int d[N];
int sum[N];
struct node{
	int l,r;
}a[N];
void solve()
{
	for(int i=0;i<=50;i++) d[i]=0;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		int l,r;
		cin>>l>>r;
		a[i]={l,r};
		d[l]++,d[r+1]--;
	}
	for(int i=1;i<=50;i++)
		sum[i]=sum[i-1]+d[i];
	queue<PII>q;
	for(int i=1;i<=50;i++)
	{
		if(sum[i]>=sum[k]&&i!=k) q.push({sum[i],i});
	}
	bool f=1;
	while(q.size())
	{
		int t=q.front().second,num=sum[t]-sum[k];
		q.pop();

		bool has=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i].l<=t&&a[i].r>=t&&(a[i].l>k||a[i].r<k))
			{
				num--;
			}
		}
		if(num>=0)
		{
			f=0;
			break;
		}
	}
	
	
	if(f) puts("YES");
	else puts("NO");
}
signed main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	//ios;
	int _t=1;
	cin>>_t;
	while(_t--) solve();
	system("pause");
	return 0;
}

C

Tea Tasting

题意:有n杯茶,每杯茶的体积是ai,有n个人品茶,每个人喝一口的体积是bi。品茶有n轮,第一轮,i号人品i号茶;第二轮,i号人品i-1号茶,1号人不品。问品茶结束后,每个人喝了多少。

思路:设对于第i杯茶,它可以完全满足[i,j]号人喝茶需求,对于个j,我们可以利用前缀和与二分求出(对b求前缀和,求sum[j]-sum[i-1]<=a[i])。那么i~j号都可以喝上完整一口(差分),剩余的茶被j+1号人喝。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define PII pair<int,int>
#define int long long
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;

using namespace std;
int n;
int a[N];
int b[N];
int sumb[N];
int d[N];
int ans[N];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) ans[i]=0,d[i]=0;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=n;i++) sumb[i]=sumb[i-1]+b[i];

	for(int i=1;i<=n;i++)
	{
		int l=0,r=n;
		while(l<r)
		{
			int mid=l+r+1>>1;
			if(sumb[mid]-sumb[i-1]>a[i]) r=mid-1;
			else l=mid;
		}
		d[i]++;d[l+1]--;
		if(l+1<=n) ans[l+1]+=a[i]-(sumb[l]-sumb[i-1]);
	}
	for(int i=1;i<=n;i++) d[i]=d[i-1]+d[i];
	for(int i=1;i<=n;i++)
		ans[i]+=d[i]*b[i];
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<" \n"[i==n];
}
signed main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	//ios;
	int _t=1;
	cin>>_t;
	while(_t--) solve();
	system("pause");
	return 0;
}

D

Triangle Coloring

题意:给定n个点,点1,2,3、4,5,6...每三个点组成一个三元组。三元组内形成一个三角形。三元组间没有边相连。现在你需要对这些点进行涂色,涂成红或蓝色,且红色、蓝色点个数都为n/2。涂色方案的价值定义为:连接不同色顶点的边的权重之和。求最大涂色价值的方案数。

思路:因为最大涂色价值,所以涂色方法是最小权重边两端颜色同,另外的点涂另一种颜色。问题转化成在m个三角形中,选择m/2个三角形涂成一红二蓝,另一半m/2个三角形涂成一蓝二红。涂色方案数为C(m,m/2)

在三角形内部,边权情况如下:

4 4 4三边权重相同,三种

4 4 2两个长边相同,一种

2 2 4两个短边相同,两种

2 3 4三边不同,一种

求组合数可以用Lucas定理。

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(0), cin.tie(0)
#define PII pair<int, int>
#define int long long
typedef long long ll;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod=998244353;
using namespace std;
int n;
int a[N];
int qmi(int a,int k)
{
	int ret=1%mod;
	while(k)
	{
		if(k&1) ret=(ll)ret*a%mod;
		k>>=1;
		a=(ll)a*a%mod;
	}
	return ret;
}
int C(int a, int b)
{
	if(a<b) return 0;
	int ret = 1;
	for (int i = 1, j = a; i <= b; i++, j--)
	{
		ret = (ll)ret * j % mod;
		ret = (ll)ret * qmi(i, mod - 2) % mod;
	}
	return ret;
}

int lucas(ll a, ll b)
{
	if (a < mod && b < mod)
		return C(a, b);
	return (ll)C(a % mod, b % mod) * lucas(a / mod, b / mod) % mod;
}

void solve()
{
	cin >> n;
	
	int ret = lucas(n/3,n/6); 
	for (int i = 1; i <= n; i++) cin >> a[i];
	int t=1;
	for(int i=1;i<=n;i+=3)
	{
		sort(a+i,a+i+2+1);
		if(a[i+2]==a[i+1])
		{
			if(a[i+1]!=a[i])//2 4 4
			{
				t*=1;
			}
			else //4 4 4
			{
				t=t%mod*3%mod;
			}
		}
		else
		{
			if(a[i+1]!=a[i]) //2 3 4
			{
				t*=1;
			}
			else //2 2 4
			{
				t=t%mod*2%mod;
			}
		}
	}
	cout<<ret%mod*t%mod<<'\n';
}
signed main()
{
	// freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
	// ios;
	int _t = 1;
	// cin>>_t;
	while (_t--)
		solve();
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值