20201004 day26 模拟(六)

1

前置cheese

排序不等式

\(a_1\leq a_2\leq ...\leq a_n,b_1\leq b_2\leq ...\leq b_n\),则

\[\sum_{i=1}^na_ib_{n-i+1}\leq \sum_{i=1}^na_ib_{d_i}\leq\sum_{i=1}^na_ib_i \]

其中\(d_1,d_2,...,d_n\)是任意一个排列
取等条件:\(a_1=a_2=a_3=...=a_n\)\(b_1=b_2=b_3=...=b_n\)

证明

\(P(n)\)表示命题:\(\sum\limits_{i=1}^na_ib_{n-i+1}\leq \sum\limits_{i=1}^na_ib_{d_i}\leq\sum\limits_{i=1}^na_ib_i\)
显然\(P(1),P(2)\)成立
假设\(P(n)\)成立,试图证明\(P(n+1)\)成立
则:

\[\sum\limits_{i=1}^na_ib_{n-i+1}\leq \sum\limits_{i=1}^na_ib_{d_i}\leq\sum\limits_{i=1}^na_ib_i \]

那么有

\[\sum\limits_{i=1}^na_ib_i+a_{n+1}b_{n+1}\ge \sum\limits_{i=1}^na_ib_{d_i}+a_{n+1}b_{n+1} \]

\[\sum\limits_{i=1}^{n+1}a_ib_i\ge \sum\limits_{i=1}^na_ib_{d_i}+a_{n+1}b_{n+1} \]

我们把右边的\(n+1\)\(d_1,d_2,...,d_n\)中任何一个交换,也可以不动,所以给原来的\(n!\)全排列乘上了\(n+1\)的方案数,那么就变成了\((n+1)!\),于是

\[\sum\limits_{i=1}^{n+1}a_ib_i\ge \sum\limits_{i=1}^{n+1}a_ib_{d_i} \]

同理有

\[\sum\limits_{i=1}^na_ib_{n-i+1}+a_{n+1}b_{n+1}\le \sum\limits_{i=1}^na_ib_{d_i}+a_{n+1}b_{n+1} \]

\[\sum\limits_{i=1}^{n+1}a_ib_{n-i+1}\le \sum\limits_{i=1}^na_ib_{d_i}+a_{n+1}b_{n+1} \]

我们把右边的\(n+1\)\(d_1,d_2,...,d_n\)中任何一个交换,也可以不动,所以给原来的\(n!\)全排列乘上了\(n+1\)的方案数,那么就变成了\((n+1)!\),于是

\[\sum\limits_{i=1}^{n+1}a_ib_{n-i+1}\le \sum\limits_{i=1}^{n+1}a_ib_{d_i} \]

\(P(n)\)成立,\(P(n+1)\)成立

solution

最小值是一个正序一个倒序,最大值是两个都正序(期望10分)
每次修改的时候二分修改的数字,每次找到修改的下标位置,修改数值,最终对答案的贡献仅仅是对当前位置的对应项。啥意思?
观察\(\rho(V\pm 1)\)或者\((\rho\pm 1)V\),仅仅是贡献了修改过的\(\rho_{\operatorname{change}}\)或者\(V_{\operatorname{change}}\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 300005;

int n, m, a[N], b[N], p[N], q[N];
LL ans1, ans2;

void solve(int * a, int * b, int w, int del)
{
	if (del == 1)
	{
		int p = upper_bound(a + 1, a + n + 1, w) - a - 1;
		a[p]++;
		ans1 += b[n - p + 1]; ans2 += b[p];
	}
	else
	{
		int p = lower_bound(a + 1, a + n + 1, w) - a;
		a[p]--;
		ans1 -= b[n - p + 1]; ans2 -= b[p];
	}
}

int main()
{
	freopen("chemist.in", "r", stdin);
	freopen("chemist.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), p[i] = a[i];
	for (int i = 1; i <= n; i++) scanf("%d", &b[i]), q[i] = b[i];
	sort(a + 1, a + n + 1); sort(b + 1, b + n + 1);//p,q原数组 a,b排序数组 
	for (int i = 1; i <= n; i++) ans1 += (LL)a[i] * b[n - i + 1], ans2 += (LL)a[i] * b[i];
	printf("%lld %lld\n", ans1, ans2);
	while (m--)
	{
		int ty, x, del; scanf("%d%d%d", &ty, &x, &del);
		if (ty == 1) solve(a, b, p[x], del), p[x] += del;
		else solve(b, a, q[x], del), q[x] += del;
		printf("%lld %lld\n", ans1, ans2);
	}
	return 0;
}

2

哭了。最想拿分的一个题,没想充分。
两个点相撞并反向,相当于互相穿过,且相对位置不变!!!!这意味着所有点的编号实质上是相对不动的。那这也太好做了吧。

先求出所有颜神最终所在的位置集合。初始状态坐标最小的颜神编号为 1。在行走过程中,若有一
个颜神从 0 走到 \(L − 1\),那么坐标最小的颜神的编号就会加 1。若有一个颜神从 \(L − 1\) 走到 0,坐标最
小的颜神的编号就会减 1。这样就可以得到最终位置的坐标最小的是哪一个颜神了。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N=100005;
int n,L,T,a[N],b[N];
int main()
{
	freopen("invert.in", "r", stdin);
	freopen("invert.out", "w", stdout);
    scanf("%d%d%d",&n,&L,&T);
    int s=1;
    for (int i=1;i<=n;i++)
    {
        int x,w;scanf("%d%d",&x,&w);
        if (w==1)
        {
            a[i]=(x+T)%L;
            if (T>=L-x) (s-=(T-L+x)/L+1)%=n;
        }
        else
        {
            a[i]=((x-T)%L+L)%L;
            if (T>=x+1) (s+=(T-x-1)/L+1)%=n;
        }
    }
    s=(s%n+n-1)%n+1;
    sort(a+1,a+n+1);
    for (int i=1;i<=n;i++) b[(s+i-2)%n+1]=a[i];
    for (int i=1;i<=n;i++) printf("%d\n",b[i]);
    return 0;
}

3

solution

\(n\le 80\)

从左侧出发,令\(F_{i,j,k}\)表示当前所在的一侧还剩\(i\)个点,另一侧有\(j\)个点,位于当前侧的第\(k\)个点的方案数。
若下一步走到另一侧,则\(F_{i,j,k}\)转移到\(F_{i,j-1,k}(1\le l \le j)\)
若下一步走到同一侧,则\(F_{i,j,k}\)转移到\(F_{i-1,j,k-1}\)\(F_{i-1,j,k}\)。最后\(F_{1,0,1}\times 2\)即为答案。
复杂度\(O(n)\)

正解

注意到每次都是在某一侧走过编号连续的一段,然后将这一段删掉,再走到另一侧。若某次走了长度为\(L\)的一段,枚举起点\(k\),方案数为

\[\sum_{k=1}^L\begin{pmatrix} L-1 \\k-1 \end{pmatrix}=2^{L-1} \]

可以先求出某一侧走了若干段的方案数,然后把两侧合并。令\(G_{i,j}\)表示走了\(i\)段,经过了\(j\)个点的方案数。枚举第一段经过的点数\(k\),由于可以任意选择连续的\(k\)个点,因此转移为

\[G_{i,j}=\sum_{k=1}^jG_{i-1,j-k}(j-k+1)2^{k-1} \]

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=4005;

int n,f[N][N], MOD;

void solve()
{
	f[0][0]=1;
	for (int i=1;i<=n;i++)
		for (int j=i;j<=n;j++)
			f[i][j]=(f[i][j-1]*2%MOD+(LL)f[i-1][j-1]*j%MOD)%MOD;
	int ans=0;
	for (int i=1;i<=n;i++)
	{
		(ans+=(LL)f[i][n]*f[i][n]%MOD)%=MOD;
		(ans+=(LL)f[i][n]*f[i-1][n]%MOD)%=MOD;
	}
	printf("%d\n",ans*2%MOD);
}

int main()
{
	freopen("walk.in", "r", stdin);
	freopen("walk.out", "w", stdout);
	scanf("%d%d",&n, &MOD);
	solve();
	return 0;
}

posted @ 2020-10-04 13:25  刘子闻  阅读(122)  评论(1编辑  收藏  举报