「6月雅礼集训 2017 Day4」暴力大神hxx
【题目大意】
给出一个n重循环,每重循环有范围$[l, r]$,其中$l$,$r$可能是之前的变量,也可能是常数。求循环最底层被执行了多少次。
其中,保证每个循环的$l$,$r$最多有一个是之前的变量。设所有常数最大值为C。
$1 \leq n \leq 26, 1\leq C \leq 10^5$
【题解】
发现构成了一个森林。
树形dp,稍微推一些循环交换顺序等等的性质,然后乘在一起就行了。
大概设f[x,i]表示到了x这个点,x的取值为i,x的子树的执行次数。
转移用个前缀和优化即可。复杂度$O(nC)$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int M = 1e5 + 10, N = 27; const int mod = 12015858; int n; int l[N], r[N]; char str[N]; inline void gin(int &x) { scanf("%s", str); if(!isdigit(str[0])) x = -(str[0] - 'a' + 1); else { x = 0; for (int i=0; str[i]; ++i) x = (x<<3) + (x<<1) + str[i] - '0'; } } int head[N], nxt[M], to[M], tot = 0; inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { // cout << u << " --> " << v << endl; add(u, v), add(v, u); } int f[N][M], s[N][M]; // 到了x这个点,x的取值为i inline void dfs(int x, int fa = 0) { for (int i=1; i<=100000; ++i) f[x][i] = 1; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fa) continue; dfs(to[i], x); int y = to[i]; for (int j=1; j<=100000; ++j) { if(l[y] < 0) { if(j <= r[y]) f[x][j] = 1ll * f[x][j] * (s[y][r[y]] - s[y][j-1]) % mod; else f[x][j] = 0; } if(r[y] < 0) { if(l[y] <= j) f[x][j] = 1ll * f[x][j] * (s[y][j] - s[y][l[y]-1]) % mod; else f[x][j] = 0; } if(f[x][j] < 0) f[x][j] += mod; } } for (int i=1; i<=100000; ++i) { s[x][i] = s[x][i-1] + f[x][i]; if(s[x][i] >= mod) s[x][i] -= mod; // if(i <= 100) cout << x << ' ' << i << ' ' << f[x][i] << endl; } } int main() { // freopen("car.in", "r", stdin); // freopen("car.out", "w", stdout); cin >> n; for (int i=1; i<=n; ++i) { gin(l[i]), gin(r[i]); // cout << l[i] << ' ' << r[i] << endl; if(l[i] < 0) adde(-l[i], i); if(r[i] < 0) adde(-r[i], i); } ll ans = 1, times; for (int i=1; i<=n; ++i) { if(l[i] < 0 || r[i] < 0) continue; dfs(i); ans = ans * (s[i][r[i]] - s[i][l[i]-1]) % mod; } ans = (ans + mod) % mod; cout << ans; return 0; }