Codeforces Round 872 (Div. 2)


A. LuoTianyi and the Palindrome String

题意:

给一个回文串s(1 <= |s| <= 50),求出最长非回文子序列的长度,如果没有非回文子序列,输出-1.

思路:

如果回文串所以字母相等,输出-1,否则输出回文串长度减一即可,因为回文串删除一个字符一定可以得到非回文串

代码:

string s;
 
void solve() {
	cin >> s;
	int n = s.size();
	s = " " + s;
	bool ok = true;
	for(int i = 1; i <= n - 1; i ++ )
		if (s[i] != s[i + 1]) {
			ok = false;
			break;
		}
	if (ok)	cout << -1 << endl;
	else	cout << n - 1 << endl;
}

 

B. LuoTianyi and the Table

题意:

给出n*m的空白矩阵和n*m(2 <= n, m <= 100)个数字,可以将数字填充在空白矩阵中,假设每个点的贡献为以该点为矩形右下角,(1, 1)为矩形左上角的一个矩形,其中的最大值减最小值。求所有点的贡献之和。

思路:

找到最大值和最小值,(1, 1)放最大值或者最小值可以使贡献和最大,两种情况取max即可。假设(1, 1)放最大值,那么(1, 2)和 (2, 1)放最小和第二小,当然,最小的要放在贡献最大的那个点,贡献最大的点的贡献次数为mm = max(n * (m - 1), m * (n - 1)), 那么另一个点为n*m - mm次。(1,1)放最小值同理。

代码:

int n, m;
int b[maxn];
 
void solve() {
	cin >> n >> m;
	int x;
	for (int i = 1; i <= n * m; i++) cin >> b[i];
	sort(b + 1, b + n * m + 1);
	int ti = n * m - 1;
	int mm = max(n * (m - 1), m * (n - 1));
	int ans1 = mm * (b[n * m] - b[1]) + (ti - mm) * (b[n * m - 1] - b[1]);
	int ans2 = mm * (b[n * m] - b[1]) + (ti - mm) * (b[n * m] - b[2]);
	cout << max(ans1, ans2) << endl;
}

 

C. LuoTianyi and the Show

题意:

现在有n个人和m(1 <= n, m <= 1e5)个座位,和一个数组x,有下面三种操作

xi == -1, 则当前这个人坐在已经坐下的人当中最左边的人的左边,如果没有人已经坐下,则坐在m号座位上;

xi == -2,则当前这个人坐在已经坐下的人当中最右边的人的右边,如果没有人已经坐下,则坐在1号座位上;

xi > 0,则坐在xi号座位上。

如果座位上有人了,就不能再坐了。

求最多能坐下多少人。

思路:

总共只有三种人:-1,-2和正整数。分三种情况考虑,-1先坐,-2先坐和正整数先坐。设n1为-1的个数,n2为-2的个数,s.size()为正整数的个数,因为同一个位置不能坐两个人,所以要用set去重。如果先坐-1,ans1 = min(m, n1 + s.size()), 先坐-2, ans2 = min(m, n2 + s.size()),如果先坐正整数的话,得考虑从哪个人开始向左右扩张,枚举一下正整数的人即可。

代码:

int n, m;
 
void solve() {
	cin >> n >> m;
	int x;
	int n1 = 0, n2 = 0;
	set<int> s;
	for (int i = 1; i <= n; i++) {
		cin >> x;
		if (x == -1)	n1++;
		else if (x == -2)	n2++;
		else s.insert(x);
	}
	int ans1 = min(m, n1 + s.size());
	int ans2 = min(m, n2 + s.size());
	int ans3 = 0;
	int al = 0;
	for (auto p : s) {
		ans3 = max(ans3, min(m, min(p - 1 - al, n1) + min(n2, m - p - (s.size() - al - 1)) + s.size()));
		al++;
	}
	cout << min(m, max({ ans1, ans2, ans3 })) << endl;
}

 

D2. LuoTianyi and the Floating Islands (Hard Version)

题意:

给一个含有n个节点的树和k个人(1 <= k <= n <= 2e5),k个人可以随机站在树上的k个节点,现在规定good点:到k个点的距离之和最小。求good点 mod 1e9 + 7的期望。

思路:

选择一个点,如果有一个分支上站的人大于k/2,那么往这个分支上移动距离之和一定会变小,不符合题意。所以通过good作一条边,两边的人数是相等的,因此只要找到good边的期望,最后答案加一就是good点的期望。如果k是奇数,那么good点一定是在中间,答案是1。如果k是偶数,枚举每一个点,假设sz[x]为x的子树的大小,让ans += C(sz[x], k/2)* C(n - sz[x], k/2)。

代码:

int qmi(ll a, ll b, ll p) { ll ans = 1; while (b) { if (b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; }

int n, k;
int sz[maxn];
int fact[maxn], infact[maxn];
 
void init() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < maxn; i++)
    {
        fact[i] = fact[i - 1] * i % mod;
        infact[i] = infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
}
 
int C(int a, int b) {
    if (a < 0 || b < 0 || a < b) return 0;
    return fact[a] % mod * infact[b] % mod * infact[a - b] % mod;
}
 
vector<int> g[maxn];
int ans = 0;
 
void dfs(int u, int fa) {
    sz[u] = 1;
    for (auto i : g[u]) {
        if (i == fa) continue;
        dfs(i, u);
        sz[u] += sz[i];
    }
    ans = (ans + C(sz[u], k / 2) * C(n - sz[u], k / 2) % mod) % mod;
}
 
void solve() {
	cin >> n >> k;
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    if (k & 1) {
        cout << 1 << endl;
        return;
    }
    dfs(1, -1);
    cout << 1 + ans * qmi(C(n, k), mod - 2, mod) % mod << endl;
}
 
signed main() {
	IOS;
	int t = 1;
	//cin >> t;
    init();
	while (t--)	solve();
}

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方哲Beans

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值