20201017 day38 模拟(十一)

1

problem

对有限集合\(A\),存在函数\(f:N→A\)具有下述性质:若\(|i-j|\)是素数,则\(f(i)≠f(j),N=\{1,2,…\}\).求有限集合A的元素的最少个数.

solution

【引理】\(\forall p\ge 2\),若\(p\)为质数,则\(p=4n+1\)\(p=4n+3,n\in \mathbb N\)
证明:①所有大于2的素数都是奇数
\(4n+1,4n+3\)表示了所有的奇数
【证明】
\(1,3,6,8\)中每两个数的差为素数,所以\(f(1),f(3),f(5),f(8)\)互不相同,\(|A|≥4\)
另一方面,令\(A=\{0,1,2,3\}\).对每一自然数\(n\),令\(f(n)=n\operatorname{mod} 4\),则在\(f(i)=f(j)\)时,\(|i-j|\)被4整除.所以不被4整除时,\(f(i)\neq f(j)\),因而\(|i-j|\)是质数。
因而\(f\)是满足条件的函数,A的元素个数最少为4.

code

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
long long read(){
	int a=0,op=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
	return a*op;
}
int n, ans = 0x3f3f3f3f, now, col[10], ans_col[10];
int main()
{
	scanf("%d", &n);
	if (n <= 6)
	{
		printf("%d\n", (n + 1) / 2);
		for (int i = 1; i <= n; i++)
			printf("%d ", (i + 1) / 2);
	}
	else
	{
		puts("4");
		for (int i = 1; i <= n; i++)
			printf("%d ", 1 + (i & 3));
		return 0;
	}
	return 0;
}

2

problem

对于给定的长\(m\)的序列\(a\),求一个长度为\(m\)的序列\(b\),满足以下性质:
\(\forall i\in[1,m],b_i\in[0,n]∩\mathbb Z\)\(\sum\limits_{i=1}^ma_ib_i\le D\)
在满足以上条件的情况下,求\(\left( \sum\limits_{i=1}^mb_i+k\min_{i=1}^mb_i\right)_{\max}\)
\(T\)组数据.

solution

首先有贪心:\(a_i\le a_j\)\(b_i\ge b_j\),将\(a\)排序,枚举有多少个\(b\)达到了上界\(n\)。若有\(s\)个达到了上界。我们设\(b_{s+1}=x\),则答案为:

\[ni+x+\left\lfloor \dfrac{D-n\sum\limits_{i=1}^sa_i-a_{s+1}x}{\sum\limits_{i=s+2}^na_i}\right\rfloor(k+m-i-1) \]

后面是形如\(x+a\left\lfloor \dfrac{bx+c}{d}\right\rfloor(a\ge 0)\)的形式,这个函数形如锯齿状,有三种可能达到最大值。
(1)开始的第一个峰值

  m
 /|
/ | /|
  |/ | /
     |/

(2)结束的最后一个峰值

          m
         /|
     /| / |/
 /| / |/
/ |/

(3)结束点

          m
         /
     /| / 
 /| / |/
/ |/

放在题中就是

  1. 尽可能提高\(\min b_i\),零头去提高\(b_s\)
  2. 尽可能提高\(b_s\),零头去提高\(\min b_i\)(虽然零头显然不足以提高)
  3. \(\min b_i\)增加1,剩下全部去提高\(b_s\)
    时间复杂度\(O(Tn\log n)\)

code

#include <bits/stdc++.h>
using namespace std;

const int Maxn = 200005;
int T, m;
long long k, n, ans, sum, D, a[Maxn];
int main()
{
	freopen("array.in", "r", stdin);
	freopen("array.out", "w", stdout);
	scanf("%d", &T);
	while (T--)
	{
		sum = ans = 0;
		scanf("%lld%d%lld%lld", &n, &m, &k, &D);
		for (int i = 1; i <= m; i++)
			scanf("%lld", &a[i]), sum += a[i];
		sort(a + 1, a + 1 + m);
		for (int i = 1; i <= m; i++)
		{
			int whole = min(n, D / sum);
			ans = max(ans, whole * (m + k - i + 1) + min(n - whole, (D - whole * sum) / a[i]) + n * (i - 1));
			if (D < a[i] * n)
			{
				ans = max(ans, D / a[i] + n * (i - 1));
				break;
			}
			if (i != m)
			{
				long long tmp = (D - a[i] * n) / (sum - a[i]) + 1;
				if (D >= tmp * sum)
					ans = max(ans, tmp * (m + k - i + 1) + min(n, (D - tmp * sum) / a[i]) + n * (i - 1));
			}
			sum -= a[i];
			D -= a[i] * n;
		}
		printf("%lld\n", ans);
	}
	return 0;
}

3

problem

你有一棵\(n\)节点的树 ,回答\(m\)个询问,每次询问给你两个整数\(l,r\),问存在多少个整数\(k\)使得从\(l\)沿着\(l\rightarrow r\)的简单路径走\(k\)步恰好到达\(k\)

solution

考虑将链拆分为\(a\)\(\operatorname{lca}(a,b)\)\(\operatorname{lca}(a,b)\)\(b\)。记\(\operatorname{dep}(x)\)表示\(x\)的深度。
\(a\)\(\operatorname{lca}(a,b)\)上的答案就是\(\operatorname{dep}(x)-\operatorname{dep}(a)=x\)\(x\)个数,也就是说\(\operatorname{dep}(x)-x=\operatorname{dep}(a)\)\(x\)个数,另一段类似,先讨论一段。

注意到前面的这是个常数,令\(b_x=\operatorname{dep}(x)-x\),所以就是查链上有多少个点\(x\)满足\(b_x\)为常数\(\operatorname{dep}(a)\),这个查分一下,可以变成查询点到根路径上有多少个点满足\(b_x\)为常数。

离线做一个树上前缀和,维护一个数组,表示每个\(b_x\)的出现次数,然后\(\text{dfs}\)\(\text{dfs}\)\(x\)时将\(b_x\)插入到这个数组中,\(\text{dfs}\)\(x\)的时候,将\(b_x\)删去,\(\text{dfs}\)到一个点的时候处理所有被离线到这个点的询问即可。总时间复杂度\(O(n+m)\)

code

4

problem

对于一个长为01序列,初始都为1.先有\(m\)条指令,第\(i\)条指令是一对数\((x_i,y_i)\),你可以选择:

  1. 记录该条指令为1,表示将\(y_i\)变为0,\(x_i\)变为1
  2. 记录该条指令为0,表示将\(x_i\)变为0,\(y_i\)变为1

输出一个长为\(m\)的01串,第\(i\)个数(0或1)表示第\(i\)条指令的情况,并使得最终仍有不小于\(\left\lfloor \dfrac{n}{2}\right\rfloor\)个数为1.

solution

看到\(\left\lfloor \dfrac{n}{2}\right\rfloor\)容易想到两两分组。刚开始我们令\((1,2)\)一组,\((3,4)\)一组,如果最后一个数是奇数则\(n\)单独一组。一组\((x,y)\)表示经过前若干个操作后可以在\(x\)\(y\)中,组与组之间互不影响。

经过一个导线\((x,y)\)后,如果之前分组\((x),(y,z)\)合并则调整为\((x,y),(z)\),如果是\((x,u),(y,v)\)则调整为\((x,y),(u,v)\)。考虑所有情况容易发现这样不会出错。构造只需要反推。复杂度\(O(n+m)\)

code

posted @ 2020-10-17 13:23  刘子闻  阅读(190)  评论(1编辑  收藏  举报