Educational Codeforces Round 143 (Rated for Div. 2)(A~D)

 复建补题记录了属于是

A.two towers

题目链接

题意:

        给两个由红色块和蓝色块搭成的塔,  每次操作可以把某个塔塔顶的方块放到另一个塔的塔顶,问是否可以通过任意次操作,使得两个塔的任意两个相邻方块颜色不同。

思路:

       考虑一种极端情况,把一个塔完全接到另一个塔上(虽然并不允许)然后遍历这个串,如果其中有一组同色色块相连,我们就可以从这个位置分成两个塔,而如果有一组以上,那无论我们怎么分都一定会有同色色块相连。

Code

#include<bits/stdc++.h>
#define debug(x) cerr << #x << "->" << x << endl;
#define int long long
using namespace std;

const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;

void solve()
{
	int n,m;
	cin >> n >> m;
	string a,b;
	cin >> a >> b;
	reverse(b.begin(),b.end());
	a += b;
	int cnt = 0;
	for(int i = 1;i < a.size();i ++)
		if(a[i] == a[i - 1])
			cnt ++;
	if(cnt <= 1) cout << "yes" << '\n';
	else cout << "no" << '\n';
}
signed main()
{
	int tt;
	cin >> tt;
	while(tt --)
		solve();
}

  B.Ideal Point

题目链接

题意

        给n条线段,定义f(x)为覆盖x的线段的数量,当一个点x的f(x)大于其他任意一点y的f(y),我们称这个f(x)是ideal的,给一个点k,问能不能通过移除任意跳线段使得k成为ideal的。

思路

        所有不包含k的线段都直接去除,接下来考虑包含k的。我们假设有两条线段包含k,切这两条线段唯一的交点为k,那么此时k就是ideal的,那么我们只要确定有这两条线段存在,把其他的线段全部删除即可,如果找不到这么两条线段,就无法使k成为ideal。

Code

#include<bits/stdc++.h>

using namespace std;
typedef pair<int,int> PII;
const int maxn = 1030 + 10;

void solve()
{
    int n,k,flag = 0,flag0 = 0;
    cin >> n >> k;
    vector<PII>p(n + 1);
    for(int i = 1;i <= n;i ++)
    {
        int x,y;
        cin >> x >> y;
        if(x == k) flag = 1;
        if(y == k) flag0 = 1;
    }
    if(flag && flag0) puts("YES");
    else puts("NO");
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt;
    cin >> tt;
    while(tt --)
        solve();
}

 C.Tea Tasting

题目链接

题意

        有n杯茶和n个人,每杯茶有ai毫升,每个人每次最多喝bi毫升。

        第一轮,第i个人喝第i杯茶,每个人喝下min(ai,bi)毫升,每杯茶减少相同毫升。

        第二轮,第i个人喝第i - 1杯茶,第一个不喝,每个人喝下min(ai - 1,bi)毫升,每杯茶减少相同毫升。

        ...

        以此类推,问最后一轮结束后每个人能喝到多少茶。

思路

         手模一下,发现第i杯茶会被第 i ~ n 这些人喝,而且每杯茶会被喝完,我们做一个b的前缀和数组sunb,对于每杯茶二分查找他会被第几个人喝完,假如被第j个人喝完,那i ~ j - 1的人都会喝到bi毫升,第i个人会喝到a[i] - sum[j - 1] + sum[i - 1]毫升,用差分数组维护一下每个人喝到了几次bi,瞎搞一通就ok了

Code

#include<bits/stdc++.h>

#define int long long
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1030 + 10;

void solve()
{
    int n;
    cin >> n;
    vector<int>a(n + 1),b(n + 1),sum(n + 1),dif(n + 1),res(n + 1);
    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 ++)
        sum[i] = sum[i - 1] + b[i];
    for(int i = 1;i <= n;i ++)
    {
        int l = 1,r = n + 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(sum[mid] - sum[i - 1] >= a[i]) r = mid;
            else l = mid + 1;
        }
        if(l == n + 1) dif[i] ++;
        else
        {
            dif[i] ++;
            dif[l] --;
            res[l] += (a[i] - (sum[l - 1] - sum[i - 1]));
        }
    }
    int tot = 0;
    for(int i = 1;i <= n;i ++)
    {
        // cout << res[i] << " \n"[i == n];
        tot += dif[i];
        res[i] += (tot * b[i]);
        cout << res[i] << " \n"[i == n];
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt;
    cin >> tt;
    while(tt --)
        solve();
}

D.Triangle  Coloring

题目链接

 题意

        给一个含n个点的带权无向图(n % 6 == 0),这个图被分成n/3个连通块,第i个连通块内点的标号为i,i+1,i+ 2,现在把这n个点染成红色和蓝色,要求红色点和蓝色点各占n/2,定义W为图中连接异色两点的边的边权和,问有多少种染色方式使得W最大。

思路

         首先如果W最大,则不应该存在三条边均同色的连通块,而又要求红蓝数量相等,那么应该有一半的环染成红红蓝,另一半染成蓝蓝红,C(n/3,n/6)为环染色的情况,接下来考虑每个环有一种染法,优先使最大的两条边异色,而如果有两条边相等且都不是最大,那么有两种染法,如果三条边均相等,那么有三种染法,遍历计算ans即可。

Code

#include<bits/stdc++.h>

#define int long long
using namespace std;
typedef pair<int,int> PII;
const int mod = 998244353;
const int maxn = 3e5;
int f[maxn];

int q_pow(int a,int b)
{
    int res = 1;
    while(b)
    {
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int inv(int p)
{
    return q_pow(p,mod - 2);
}
void solve()
{
    int n;
    cin >> n;
    vector<int>w(n + 1);
    for(int i = 1;i <= n;i ++) cin >> w[i];
    int ans = 1;
    for(int i = 1;i <= n;i += 3)
    {
        vector<int>b = {w[i], w[i + 1], w[i + 2]};
        sort(b.begin(),b.end());
        if(b[0] == b[1] && b[1] == b[2]) ans = (ans * 3) % mod;
        if(b[0] == b[1] && b[1] < b[2]) ans = (ans * 2) % mod;
    }
    int info = ((f[n / 3] * inv(f[n / 6])) % mod * inv(f[n / 3 - n / 6])) % mod;
    cout << ans * info % mod << endl;

}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    f[0] = 1;
    for(int i = 1;i <= maxn;i ++)
        f[i] = (f[i - 1] * i) % mod;
    // int tt;
    // cin >> tt;
    // while(tt --)
        solve();
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值