Codeforces Global Round 17

\(\tt noip\) 之后的第一场线上赛,感觉手感退化了很多啊,不知道上红的目标能不能如期实现呢?

D. Not Quite Lee

题目描述

数轴上有 \(n\) 个窗口,第 \(i\) 个窗口的长度为 \(b_i\)(包含这么多连续的整数),定义一个窗口的权值为包含数字的和,问有多少个窗口的子序列满足存在一种滑动方案使得权值和为 \(0\)

\(n\leq 2\cdot 10^5\)

解法

考虑调整法,一开始可以取总和为 \(\sum \frac{c_i(c_i-1)}{2}\) 的窗口组合,那么滑动相当于把权值 \(+c_i\) 或者 \(-c_i\),那么合法的充要条件是存在序列 \(\{x_i\}\) 满足 \(\sum c_i\cdot x_i=\sum\frac{c_i(c_i-1)}{2}\)

根据裴蜀定义可以转化为 \(\sum\frac{c_i(c_i-1)}{2}|\gcd(c_1,c_2...c_n)\),但是好像还是不可做。

我们观察 \(\sum\frac{c_i(c_i-1)}{2}\) 有什么性质,其中特殊的是 \(2\) 这个常数,这提示我们可以着重讨论奇偶性。

然后观察到如果原序列中存在奇数那么一定合法,因为此时一定满足 \(\sum \frac{c_i(c_i-1)}{2}|\gcd\),尝试扩展这个观察,也就是把每个子序列在满足 \(\gcd|2^l\) 的最大的 \(l\) 处统计。

对于 \(l>0\),我们把限制拆成 \(\sum\frac{c_i(c_i-1)}{2}|2^l\and \sum\frac{c_i(c_i-1)}{2}|\frac{g}{2^l}\),也就是满足 \(c_i|2^l\and c_i\not| 2^{l+1}\) 的有偶数个并且至少有 \(1\) 个,所以可以用容斥原理简单计算。

#include <cstdio>
const int M = 200005;
const int MOD = 1e9+7;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,a[M],pw[M];
signed main()
{
	n=read();pw[0]=1;
	for(int i=1;i<=n;i++)
	{
		int x=read(),cnt=0;
		while(x%2==0) cnt++,x/=2;
		a[cnt]++;
		pw[i]=pw[i-1]*2%MOD;
	}
	int ans=pw[n]-pw[n-a[0]],y=n-a[0];
	for(int i=1;i<=30;i++)
	{
		int x=y;y-=a[i];
		if(x-1<=y) continue;
		ans+=pw[x-1]-pw[y];
	}
	printf("%lld\n",(ans%MOD+MOD)%MOD);
}

E. AmShZ and G.O.A.T.

题目描述

定义一个序列为坏当且仅当严格大于平均数的数量 大于 严格小于平均数的数量。

问最少删除多少个元素使得最后的序列的任何子序列都不为坏。

\(n\leq 2\cdot 10^5\),保证原序列单增。

解法

考虑转化判据,原序列的任何子序列不为坏当且仅当原序列的任何一个长度为 \(3\) 的子序列不为坏,必要性显然,下证充分性:

考虑对于如果 \(a_{i+1}-a_i<a_i-a_1\),那么 \(\{1,i,i+1\}\) 就是一组坏的序列。否则我们可以知道对于任何一个子序列都有 \(c_{\lceil\frac{k}{2}\rceil}\leq AVG\)(因为是凸函数,中间位置一定在下方),这足以说明不存在坏的子序列。

就上面这个简单的证明我证了一周,当然是边学文化课有空余时间再证的

那么我们只需要保证 \(a_{i+1}-a_i\geq a_i-a_1\) 就可以得到好的序列,考虑一个一个加数,那么新数与首项的距离每次一定翻倍,所以在非常数序列的情况下,序列长度是 \(O(\log a)\) 的。

所以我们枚举首项,然后贪心地找最近合法的下一项,注意特判相等的情况,那么时间复杂度 \(O(n\log n\log a)\)

总结

本题的难点其实是结论,这种类型就是判断最基本的情况就有了充分性。

证明方法难以用语言表达,自己体会一下吧

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n,ans,a[M];
signed main()
{
	T=read();
	while(T--)
	{
		n=read();ans=0;
		for(int i=1;i<=n;i++)
			a[i]=read();
		for(int i=1;i<=n;i++)
		{
			if(a[i]==a[i-1]) continue;
			int j=i,res=1;
			while(j<=n)
			{
				j=lower_bound(a+j+1,
				a+n+1,2*a[j]-a[i])-a;
				if(j<=n) res++;
			}
			ans=max(ans,res);
		}
		printf("%d\n",n-ans);
	}
}
上一篇:JNI原理 System.loadLibrary源码分析


下一篇:c – 从32位进程调用64位dll上的LoadLibrary