Codeforces Round 872 (Div. 2) A-D2

题目链接:Dashboard - Codeforces Round 872 (Div. 2) - Codeforces

A - LuoTianyi and the Palindrome String

解题思路:如果全部相等就不行要不然答案就是n或者n-1了。

#include <bits/stdc++.h>
using namespace std;
const int mx = 2e5 + 10;
using ull = unsigned long long;
using ll = long long;


int main() {
	auto check1 = [](string &s) {
		for (int i=1;i<s.length();i++) {
			if (s[i] != s[i-1])
				return false;
		}	
		return true;
	};
	auto check2 = [](string &s) {
		int len = s.length();
		for (int i=0; i<len/2;i++) {
			if (s[i] != s[len-1-i]) {
				return false;
			}
		} 
		return true;
	};
	
	int t;
	scanf("%d", &t);
	while (t--) {
		string s;
		cin>>s;
		if (check1(s)) {
			puts("-1");
			continue;
		}
		if (!check2(s)) {
			printf("%d\n", s.length());
		} else {
			printf("%d\n", s.length()-1);
		}
	}
    return 0;
}

B - LuoTianyi and the Table

解题思路:n-1 * m的格子肯定是最大值减去最小值的,然后剩下一行就看是最大值减去次小值还是次大值减去最小值更好了。

#include <bits/stdc++.h>
using namespace std;
const int mx = 2e2 + 10;
using ull = unsigned long long;
using ll = long long;
#define inf 0x3f3f3f3f

int a[mx*mx];

int main() {

	
	int t;
	scanf("%d", &t);
	while (t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i=1;i<=n*m;i++) {
			scanf("%d", a + i);
		}
		sort(a + 1, a + 1 + n * m);
		if (n < m)  swap(n, m);
		
		ll ans1 = 1ll * (n - 1) * m * (a[n*m] - a[1]) + (m-1) * (a[n*m] - a[2]);
		ll ans2 = 1ll * (n - 1) * m * (a[n*m] - a[1]) + (m-1) * (a[n*m-1] - a[1]);
		printf("%lld\n", max(ans1, ans2));
	}
    return 0;
}

C - LuoTianyi and the Show

解题思路:贪心枚举哪个固定值先放,然后就沿着这个值的位置两边展开就行了。

#include <bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 10;
using ull = unsigned long long;
using ll = long long;
#define inf 0x3f3f3f3f

int a[mx];

int main() {

	
	int t;
	scanf("%d", &t);
	while (t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		set <int> seat;
		int num1 = 0, num2 = 0;
		for (int i=1;i<=n;i++) {
			scanf("%d", a+i);
			if (a[i] == -1)
				num1++;
			else if (a[i] == -2)
				num2++;
			else
				seat.insert(a[i]);
		}
		int ans = max(num1, num2) + (int)seat.size();
		int i = 1;
		for (auto it=seat.begin(); it != seat.end(); it++, i++) {
			ans = max(ans, min(*it - i, num1) + min(m - *it - ((int)seat.size() - i), num2) + (int)seat.size());	
		}
		printf("%d\n", min(ans, m));
	}
    return 0;
}

D2 - LuoTianyi and the Floating Islands (Hard Version)

解题思路:对于k为奇数来说,不管k个点怎样分布,肯定只有一个点满足条件。试想一下你现在找到了一个x点他到所有k的点的距离最小。当你任意移动x一个位置,肯定大于x这个点的所有距离,因为k不是偶数无法使得移动之后一半点增加1一半点减小一。所以当k是奇数的时候答案是1。如果k是偶数的情况下,那么就存在链的情况使得一种k点分布的情况下有多个点满足条件。首先在C(n,k)的分布情况下肯定都至少有一个点满足最小的条件。为了防止我们重复计算,当有链的情况下肯定是不值1个点满足最小值。并且把k分成2分,如果一个边(u,v)满足条件,那么以v为子树的点有k/2个,剩下的k/2就不在v这棵子树上。因此我们可以枚举边的贡献,来防止重复计算,因为一个n个点链他的边就是n-1条。所以不会重复计算C(n,k)中至少一次的贡献。

#include <bits/stdc++.h>
using namespace std;
#define k_m (k / 2 + 1)

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

using ll = long long;

vector <int> vec[mx];
ll c[mx];
int siz[mx];
int n,k;
ll base;

ll qpow(ll x, ll y)
{
    ll ans = 1;
    while (y) {
        if (y & 1) ans = ans * x % mod;
        y >>= 1;
        x = x * x % mod;
    }
    return ans;
}

ll C(int nn, int mm)
{
    if (nn < mm)
        return 0;
    return c[nn] * qpow(c[mm], mod-2) % mod * qpow(c[nn-mm], mod-2) % mod;
}

ll dfs(int u, int f)
{
    ll ans = 0;
    siz[u] = 1;
    for (int v: vec[u]) {
        if (v == f)
            continue;
        ans += dfs(v, u);
        siz[u] += siz[v];
        ans += (C(siz[v], k/2) * C(n-siz[v], k/2)) % mod;
        ans %= mod;
    }
    return ans;
}


int main()
{
    c[0] = 1;
    scanf("%d%d", &n, &k);
    for (int i=1;i<=n;i++) {
        c[i] = c[i-1] * i % mod;
    }
    base = C(n, k);
    ll ans = base;
    for (int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d", &u, &v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    if (k & 1) {
        puts("1");
        return 0;
    }
    ans += dfs(1, 0);
    ans %= mod;
    printf("%lld\n", ans * qpow(base, mod-2) % mod);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值