2024.1.26 大寄特寄

很好的数学专题,让我发疯

A.

居然直接加了个限制,要求是对于连续的子序列,要求相等,关键是一定有解,用到了鸽笼原理

假设对两个数列求前缀和之后,分别是An,Bn

最终要得到 Ai - Aj = Bk - Bl

但是这样肯定是很麻烦的,要枚举,但是如果移项就可以得到一个有相同格式的式子

Ai - B= Aj - Bl 

下标从0开始,对于Aj - Bi中的i,找到一个最小的 j 让差值为非负,那这个差值的范围一定是 [0,n),又下标是从 0 到 n,所以最多 n 种可能的结果,但实际有 n + 1种结果,说明一定有两对下标满足,那么这样就找到最终答案了。

查看代码
#include<bits/stdc++.h>

using namespace std;
const int MAXN = 1e6 + 10;
typedef long long LL;

int n;
LL a[MAXN], b[MAXN];
pair<int, int> vis[MAXN];

void print(int m, int l, int r)
{
	cout<< l - vis[m].first << '\n';
	for(int i = vis[m].first + 1;i <= l;i++) cout << i << " \n"[i==l];
	cout<< r - vis[m].second << '\n';
	for(int i = vis[m].second + 1;i <= r;i++) cout << i << " \n"[i==r];
	return ;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> n;
	for(int i = 1;i <= n;i++) cin>> a[i], a[i] += a[i-1];
	for(int i = 1;i <= n;i++) cin>> b[i], b[i] += b[i-1], vis[i].first = vis[i].second = -1;
	vis[0].first = -1;
	int poi = 0;
	for(int i = 0;i <= n;i++)
	{
		while(b[poi] < a[i]) poi++;
		int m = b[poi] - a[i];
		if(vis[m].first != -1)
		{
			print(m, i, poi);
			return 0;
		}
		vis[m] = {i, poi};
	}
}

 

B

关键词:组合数学,秦九韶

题目链接

题解链接

 

C

题目链接

关键词:高斯消元 组合数学 逆矩阵

一开始以为是通过数学公式,求极限来算,结果是求每个点经过次数的期望,从点的经过期望来求边的经过期望。

相连的两点间期望相互制约,通过这个建立n个n-1元的一次方程,通过高斯消元求解即可。

最后把边的期望排序就能算出结果。

 

L

怎么说呢,虽然猜到了最终肯定是把点的权排序,按个取,但是没想到怎么处理边权

一直在想怎么在点和边上怎么取舍,但实际上,对于两点一边,总共就两种情况。

一种情况是,双方各染色一个点

另一种情况就是,一方染了两个点,得到了边权

那这样最终的结果,要么就是一方得到整条边的权,要么就是双方都得不到

由于最终求得是得分的差值,那么就不关注究竟是谁得到了这条边,只要最终得到的差值对就行了。

如果将边权一分为二,分别加到两个端点上,无疑是符合最终结果的。

这个题和上一次训练的期望比较类似,既然问号有可能是o也可能是x,那连击的长度就有两种可能,一种是原长l,一种是l+1,一半一半的概率,就是l+0.5了

posted @ 2024-01-26 23:11  是谁不可理喻  阅读(25)  评论(0)    收藏  举报