首页 > 其他分享 >CF1540E Tasty Dishes

CF1540E Tasty Dishes

时间:2024-02-17 17:34:25浏览次数:20  
标签:le Dishes limits int sum right Tasty CF1540E left

Description

初始有 \(n\) 个数 \(a_i\),以及若干条有向边 \((u_i,v_i)\),保证 \(u_i<v_i\)。

一轮操作会形如下面两个过程:

  • 首先 \(\forall i,a_i:= \max(a_i,ia_i)\)。
  • 然后 \(\forall i,a'_i:= a_i+\sum\limits_{(i,j)\in E}\max(a_j,0)\),最后 \(\forall i,a_i:= a'_i\)。

\(q\) 次询问或修改,询问形如 \((k,l,r)\),你需要回答进行从初始状态操作 \(k\) 轮后的 \(\sum\limits_{i=l}^ra_i\)。修改形如 \((i,x)\),把初始的 \(a_i\) 加上 \(x\)。

\(1\le n\le 300,|a_i|\le i\)。

\(1\le q\le 2\times 10^5,1\le k,x\le 10^3\)。

Solution

注意到如果 \(i\) 可以复制 \(j\),且 \(j\) 在 \(d_j\) 天后 \(a_j>0\),因为 \(i<j,a_i\ge -i\),所以 \(a_i\) 在 \(d_j+1\) 天后也可以 \(>0\)。所以可以 \(O(n^2)\) 计算出 \(d_i\)。

由于修改 \(x>0\),所以每个初始的 \(a_i\) 至多只会有一次从 \(\le 0\) 到 \(>0\) 的跨越,所以 \(d_i\) 只会更改 \(O(n)\) 次。所以可以 \(O(n^3)\) 维护出开始和每次修改后的 \(d_i\)。

对于一次询问,考虑所有点对询问的贡献,设 \(A_{i,j}=j[(i,j)\in E\vee i=j]\),\(e_i\) 为长度为 \(n\) 的列向量且 \(e_{i,j}=[i=j]\),即 \([e_1,e_2,\cdots,e_n]=I\)。

那么答案就是:

\[\left(\sum\limits_{i=l}^re_i^T\right)\left(\sum\limits_{d_i\le k}A^{k-d_i}e_ia_i\right)+\sum\limits_{i=l}^r[d_i>k]a_i \]

右边那个是好求的,每次询问 \(O(n)\) 扫一遍 \([l,r]\) 即可。

左边也是可以求的,但是 \(A\) 太大了,而且分离出右边列向量的 \([l,r]\) 之间的数比较困难,于是进一步化简。

由于 \(A\) 为上三角矩阵,所以其特征多项式为 \(f(\lambda)=\prod\limits_{i=1}^n(\lambda-A_{i,i})\)。又由于 \(\forall i,A_{i,i}=i\),所以 \(A\) 有 \(n\) 个特征值为 \(1,2,\cdots,n\)。考虑求出每个特征值 \(i\) 的特征向量 \(v_i\)。

由于 \(Av_i=iv_i\),所以有 \(A\times [v_1,v_2,\cdots,v_n]=[v_1,2v_2,\cdots ,nv_n]\)。设 \(v_{i,i}=1\),那么根据 \((A-iI)v_i=0\) 可以解方程求出所有的 \(v_i\)。

不难发现 \(V=[v_1,v_2,\cdots,v_n]\) 为上三角矩阵,所以 \(v_i\) 线性无关,所以可以将 \(e_i\) 分解为 \(e_i=\sum\limits_{j=1}^nC_{i,j}v_{j}\) 的形式。那么 \(VC^T=I\),直接求逆即可得到 \(C\) 矩阵。

带回原式:

\[\begin{aligned}f(k,l,r)&=\left(\sum\limits_{i=l}^re_i^T\right)\left(\sum\limits_{d_i\le k}A^{k-d_i}e_ia_i\right)\\&=\left(\sum\limits_{i=l}^re_i^T\right)\left(\sum\limits_{d_i\le k}A^{k-d_i}\sum\limits_{j=1}^nC_{i,j}v_j\cdot a_i\right)\\&=\left(\sum\limits_{i=l}^re_i^T\right)\left(\sum\limits_{d_i\le k}a_i\sum\limits_{j=1}^nj^{k-d_i}v_jC_{i,j}\right)\quad\quad(Av_i=iv_i)\end{aligned} \]

这样的话右边列向量 \([l,r]\) 的值就可以分离了:

\[\begin{aligned}f(k,l,r)&=\sum\limits_{d_i\le k}a_i\sum\limits_{j=1}^nj^{k-d_i}C_{i,j}\sum\limits_{p=l}^rv_{j,p}\\&=\sum\limits_{j=1}^nj^k\left(\sum\limits_{p=l}^rv_{j,p}\right)\sum\limits_{d_i\le k}j^{-d_i}a_iC_{i,j}\end{aligned} \]

于是对于每个 \(j\) 开一个树状数组,维护每个 \(1\le k\le n\) 的 \(t_{j,k}=\sum\limits_{d_i\le k}j^{-d_i}a_iC_{i,j}\),每次询问和修改的时候枚举 \(j\),修改相当于区间操作,查询相当于单点查询,使用树状数组单次复杂度为 \(O(n\log n)\),这部分复杂度为 \(O(qn\log n)\)。

每次重新求 \(d_i\) 时重构一次树状数组即可,每次复杂度为 \(O(n^2)\) 或 \(O(n^2\log n)\)。于是总复杂度为 \(O(n^3+qn\log n)\) 或 \(O(n^3\log n+qn\log n)\)。

// Problem: Tasty Dishes
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1540E
// Memory Limit: 62 MB
// Time Limit: 10000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define eb emplace_back
#define pb pop_back
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define pc putchar
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

using namespace std;
typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int> tu;
bool Mbe;

const int N = 350;
const int K = 1e3 + 100;
const int P = 1e9 + 7;

int n, q, L, a[N], d[N], pw[N][K], ipw[N][K];
int A[N][N], V[N][N], C[N][N], T[N][N << 1], B[N][N];
vector<int> g[N];

struct BIT {
	int t[N];
	int lb(int x) { return x & -x; }
	void clr() { for (int i = 1; i <= n + 1; i++) t[i] = 0; }
	void upd(int x, int y) { for (int i = x; i <= n + 1; i += lb(i)) (t[i] += y) %= P; }
	int qry(int x) { int res = 0; for (int i = x; i; i -= lb(i)) (res += t[i]) %= P; return res; }
	void add(int l, int x) { l++, upd(l, x); }
	int qlr(int x) { return x = min(x + 1, n + 1), qry(x); }
} b[N];

int qpow(int p, int q) {
	int res = 1;
	for (; q; q >>= 1, p = 1ll * p * p % P)
		if (q & 1) res = 1ll * res * p % P;
	return res;
}

void init() {
	for (int i = 1; i <= n; i++) A[i][i] = i;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) 
			for (int k = 1; k <= n; k++) T[j][k] = A[j][k];
		for (int j = 1; j <= n; j++) (T[j][j] += P - i) %= P;
		V[i][i] = 1;
		for (int j = i - 1; j; j--) {
			int tp = 0;
			for (int k = j + 1; k <= i; k++) 
				(tp += P - 1ll * V[k][i] * T[j][k] % P) %= P;
			V[j][i] = 1ll * tp * qpow(T[j][j], P - 2) % P;
		}
	}
	memset(T, 0, sizeof(T));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			T[i][j] = V[i][j];
	for (int i = 1; i <= n; i++) T[i][i + n] = 1;
	for (int i = 1; i <= n; i++) {
		int p = i;
		for (int j = i + 1; j <= n; j++)
			if (T[j][i]) { p = j; break; }
		swap(T[i], T[p]);
		int iv = qpow(T[i][i], P - 2);
		for (int j = 1; j <= n; j++) {
			if (i == j) continue;
			int tp = 1ll * T[j][i] * iv % P;
			for (int k = i; k <= (n << 1); k++)
				(T[j][k] += P - 1ll * tp * T[i][k] % P) %= P;
		}
		for (int j = 1; j <= (n << 1); j++) T[i][j] = 1ll * T[i][j] * iv % P;
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			C[j][i] = T[i][j + n];
	memset(T, 0, sizeof(T)); 
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			(V[i][j] += V[i - 1][j]) %= P;
}

void getd() {
	for (int i = 1; i <= n; i++) 
		if (a[i] > 0) d[i] = 0;
		else d[i] = 2e9;
	for (int i = n; i; i--)
		for (int j : g[i]) d[i] = min(d[i], d[j] + 1);
	for (int j = 1; j <= n; j++) {
		b[j].clr();
		for (int i = 1; i <= n; i++) 
			if (d[i] <= n) b[j].add(d[i], 1ll * (P + a[i]) % P * C[i][j] % P * ipw[j][d[i]] % P);
	}
}

void solve() {
	n = rd();
	for (int i = 1; i <= n; i++) a[i] = rd();
	for (int i = 1; i <= n; i++) {
		int iv = qpow(i, P - 2);
		pw[i][0] = ipw[i][0] = 1;
		for (int j = 1; j <= 1000; j++)
			pw[i][j] = 1ll * pw[i][j - 1] * i % P,
			ipw[i][j] = 1ll * ipw[i][j - 1] * iv % P;
	}
	for (int i = 1, x, y; i <= n; i++) {
		x = rd();
		for (int j = 1; j <= x; j++) 
			y = rd(), g[i].eb(y), A[i][y] = y;
	}
	init(), getd();
	q = rd();
	while (q--) {
		int op, l, r, k, x, y;
		op = rd();
		if (op == 1) {
			k = rd(), l = rd(), r = rd();
			int res = 0;
			for (int j = 1; j <= n; j++) 
				(res += 1ll * (V[r][j] - V[l - 1][j] + P) % P * pw[j][k] % P * b[j].qlr(k) % P) %= P;
			for (int i = l; i <= r; i++)
				if (d[i] > k) (res += (P + a[i]) % P) %= P;
			wr(res), pc('\n');
		} else {
			x = rd(), y = rd();
			a[x] += y;
			if (a[x] > 0 && a[x] - y <= 0) getd();
			else if (d[x] <= n) {
				for (int j = 1; j <= n; j++) 
					if (d[x] <= n) b[j].add(d[x], 1ll * y * C[x][j] % P * ipw[j][d[x]] % P);
			}
		}
	}
}

bool Med;
int main() {
	// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cerr << (&Mbe - &Med) / 1048576.0 << " MB\n";
	#ifdef FILE
		freopen("1.in", "r", stdin);
		freopen("1.out", "w", stdout);
	#endif
	int _ = 1;
	// cin >> _;
	while (_--) solve();
	cerr << (int)(1e3 * clock() / CLOCKS_PER_SEC) << " ms\n";
	return 0;
}

标签:le,Dishes,limits,int,sum,right,Tasty,CF1540E,left
From: https://www.cnblogs.com/Ender32k/p/18018145

相关文章

  • PyQt/PySide's qwindows.dll qwindowsvistastyle.dll is corrupted by UPX
    Windows1064-bitsPython3.8.1064-bitsPySide25.15.2PyInstaller4.3UPX4.1.0itraises:"ThisapplicationfailedtostartbecausenoQtplatformplugincouldbeinitialize"Solutioninspecfiles,addupx_exclude=['qwindows.dll'......
  • 塔斯汀的“中国汉堡”并不tasty
    文|螳螂观察作者|易不二华莱士门徒作为快餐消费市场的两大霸主——麦当劳、肯德基,自入华以来,从来不缺模仿者、挑战者。从福建起家、已经成为了万店品牌的华莱士,无疑是最成功的一个。得益于被餐饮界称之为“福建模式”的门店合伙制,2001年在福州开出第一家门店的华莱士,经过了20多......
  • JOISC2019 ふたつの料理 / Two Dishes / 两道料理
    好题!考虑一个暴力DP:\(f(i,j)\)表示前\(i\)个\(A\),前\(j\)个\(B\),最大价值。将\(a,b\)前缀和。令\(A_i=S_i-a_i\),\(B_j\)同理,那么式子化成\(f(i,j)=\max\{f(......
  • CF580D Kefa and Dishes
    有n个菜(0<n<=18)第i个菜的满意度为a[i](0<=ai<=10^9),有k个规则,如果在吃完第xi个菜之后吃了第yi个菜,会额外获得ci的满意度。kefa要吃m道任意的菜(0<m<=n),但是他希望自己吃菜的......