1. 程式人生 > 實用技巧 >qbxt DAY 6 T3 柯西不等式和拉格朗日不等式

qbxt DAY 6 T3 柯西不等式和拉格朗日不等式

qbxt DAY 6 T3

其實主要是對拉格朗日不等式的瞭解和認識。

\((\sum a_i^2)(\sum b_i^2)=(\sum a_ib_i)^2+\sum\limits_{1\leq i< j\leq n}(a_ib_j-a_jb_i)^2\)

柯西不等式:

\((\sum a_i^2)(\sum b_i^2)\geq (\sum a_ib_i)^2\)

把兩邊開根

\(\sqrt{(\sum a_i^2)} \sqrt{(\sum b_i^2)}\geq (\sum a_ib_i)\)

可以看成兩個\(n\)維向量\((a_1,a_2,...,a_n)\)\((b_1,b_2,...,b_n)\)

則原式就是他們的模長之積大於等於點積

\(\vec{m}\cdot\vec{n}=|\vec{m}|\cdot|\vec{n}|\cdot \cos<\vec{m},\vec{n}>\)\(\cos<\vec{m},\vec{n}>\ \leq 1\)

則不等式得證

或者直接用拉格朗日不等式證明,因為\(\sum\limits_{1\leq i< j\leq n}(a_ib_j-a_jb_i)^2 \geq 0\),所以不等式得證

證明拉格朗日不等式

首先展開

\(\sum\limits_{1\leq i< j\leq n}(a_ib_j-a_jb_i)^2=\sum\limits_{i<j}(a_i^2b_j^2-2a_ib_ia_jb_j+a_j^2b_i^2)\)

先看前後兩項

\(\sum\limits_{i,j}a_i^2b_j^2-\sum\limits_{i=j}a_i^2b_j^2 \)

前面的\(i,j\)是獨立的,可以單獨拿出來

\(\sum\limits_ia_i^2\sum\limits_jb_j^2\)

中間那一項\(\sum\limits_{i<j}2a_ib_ia_jb_j\),可以把\(i\)提出來,並且把\(i,j\)的位置換一下,也就變成了

\[\begin{aligned}& \sum\limits_{i<j}a_ib_ia_jb_j+\sum\limits_{i>j}a_ib_ia_jb_j \\& =\sum\limits_{i\neq j}a_ib_ia_jb_j\\& =\sum\limits_{i,j}a_ib_ia_jb_j-\sum\limits_{i=j}a_ib_ja_jb_i\end{aligned} \]

原式就是

\[ \begin{aligned}& \sum\limits_ia_i^2\sum\limits_jb_j^2 -\sum\limits_{i}a_i^2b_i^2-\sum\limits_{i,j}a_ib_ia_jb_j+\sum\limits_{i}a_i^2b_i^2 \\&= (\sum a_i^2)(\sum b_i^2)-(\sum a_ib_i)^2 \end{aligned}\]

則等式得證

對於這道題來說,就只需要維護這三個值的樹上字首和就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read()
{
	char s = getchar(), last = '0';
	ll ans = 0;
	while(s < '0' || s > '9') last = s, s = getchar();
	while(s >= '0' && s <= '9') ans = ans * 10 + s - '0', s = getchar();
	if(last == '-') ans = -ans;
	return ans;
}
const ll mod = 998244353;
const int  N = 500005;
ll p, n, q, t, l, r, ans, a2[N], b2[N], a[N], b[N], ab[N];
int low(int x){return x & (-x);}
void add1(int now, ll v)
{
	while(now <= n)
	{
		a2[now] = (a2[now] + v) % mod;
		now += low(now);
	}
}
void add2(int now, ll v)
{
	while(now <= n)
	{
		b2[now] = (b2[now] + v) % mod;
		now += low(now);
	}
}
void add3(int now, ll v)
{
	while(now <= n)
	{
		ab[now] = (ab[now] + v) % mod;
		now += low(now);
	}
}
ll query1(int now)
{
	ll rt = 0;
	while(now)
	{
		rt += a2[now];
		now -= low(now);
	}
	return rt % mod;
}
ll query2(int now)
{
	ll rt = 0;
	while(now)
	{
		rt += b2[now];
		now -= low(now);
	}
	return rt % mod;
}
ll query3(int now)
{
	ll rt = 0;
	while(now)
	{
		rt += ab[now];
		now -= low(now);
	}
	return rt % mod;
}
ll qr1(int l, int r)
{
	return (query1(r) - query1(l - 1) + mod) % mod;
}
ll qr2(int l, int r)
{
	return (query2(r) - query2(l - 1) + mod) % mod;
}
ll qr3(int l, int r)
{
	return (query3(r) - query3(l - 1) + mod) % mod;
}
int main()
{
	cin>>n>>q;
	for(int i = 1; i <= n; i ++)
	{
		a[i] = read();
		add1(i, a[i] * a[i] % mod);
	}
	for(int i = 1; i <= n; i ++)
	{
		b[i] = read();
		add2(i, b[i] * b[i] % mod);
		add3(i, a[i] * b[i] % mod);
	}
	for(int i = 1; i <= q; i ++)
	{
		t = read();
		if(t == 1)
		{
			l = read(), r = read();
			ans = qr3(l, r);
			ans = (-ans * ans + mod * mod) % mod;
			ans = (ans + qr1(l, r) * qr2(l, r)) % mod;
			printf("%lld\n", ans);
		}
		if(t == 2)
		{
			p = read(), l = read(), r = read();
			add1(p, (l * l - a[p] * a[p] + mod * mod) % mod);
			add2(p, (r * r - b[p] * b[p] + mod * mod) % mod);
			add3(p, (l * r - a[p] * b[p] + mod * mod) % mod);
			a[p] = l, b[p] = r;
		}
	}
}