牛客挑戰賽30c++
隨便枚舉三個位置,而後二維前綴和便可。優化
# include <bits/stdc++.h> using namespace std; typedef long long ll; int sum[505][505]; int n, a[505]; ll ans; int main() { int i, j, k; scanf("%d", &n); for (i = 1; i <= n; ++i) scanf("%d", &a[i]); for (i = n; i; --i) { for (j = 1; j <= n; ++j) sum[i][j] = sum[i + 1][j]; for (j = 1; j <= a[i]; ++j) ++sum[i][j]; } for (i = 1; i <= n; ++i) for (j = i + 1; j <= n; ++j) for (k = j + 1; k <= n; ++k) if (a[i] < a[k] && a[i] < a[j] && a[k] < a[j]) ans += sum[k + 1][a[j] + 1]; printf("%lld\n", ans); return 0; }
枚舉中位數,把小的設爲 \(-1\),大的設爲 \(1\),而後前綴和找爲 \(0\) 的區間。
被肥雞卡常了ui
//time limit exceeded # include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(10005); const int mod(1e9 + 7); inline void Inc(int &x, const int y) { x = x + y >= mod ? x + y - mod : x + y; } inline void Dec(int &x, const int y) { x = x - y < 0 ? x - y + mod : x - y; } inline int Add(int x, const int y) { return x + y >= mod ? x + y - mod : x + y; } inline int Sub(int x, const int y) { return x - y < 0 ? x - y + mod : x - y; } inline int Pow(ll x, int y) { ll ret = 1; for (; y; y >>= 1, x = x * x % mod) if (y & 1) ret = ret * x % mod; return ret; } int n, p[maxn], pw[maxn], pw2[maxn], t[maxn << 1], ans, s[maxn]; int main() { int i, j, ret; scanf("%d%d", &n, &pw[1]), pw[0] = 1; for (i = 1; i <= n; ++i) scanf("%d", &p[i]); for (i = 2; i <= n; ++i) pw[i] = (ll)pw[i - 1] * pw[1] % mod; for (i = 0; i <= n; ++i) pw2[i] = Pow(pw[i], n); for (i = 1; i <= n + n; ++i) { for (j = 1; j <= n; ++j) if (p[j] + p[j] < i) s[j] = -1; else if (p[j] + p[j] > i) s[j] = 1; else s[j] = 0; t[maxn] = 1, ret = 0; for (j = 1; j <= n; ++j) { s[j] += s[j - 1]; Inc(ret, (ll)t[maxn + s[j]] * pw[j] % mod); Inc(t[s[j] + maxn], pw2[j - 1]); } Inc(ans, (ll)ret * i % mod); for (j = 1; j <= n; ++j) t[s[j] + maxn] = 0; } printf("%d\n", ans); return 0; }
枚舉一個根而後樹形 \(DP\),轉移是一個組合數。
優化的話就是換根 \(DP\)。spa
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(1e5 + 5); const int mod(998244353); inline void Inc(int &x, const int y) { x = x + y >= mod ? x + y - mod : x + y; } inline void Dec(int &x, const int y) { x = x - y < 0 ? x - y + mod : x - y; } inline int Add(int x, const int y) { return x + y >= mod ? x + y - mod : x + y; } inline int Sub(int x, const int y) { return x - y < 0 ? x - y + mod : x - y; } inline int Pow(ll x, int y) { ll ret = 1; for (; y; y >>= 1, x = x * x % mod) if (y & 1) ret = ret * x % mod; return ret; } struct Edge { int to, next; }; int n, first[maxn], size[maxn], fac[maxn], inv[maxn], f[maxn], ans, cnt; Edge edge[maxn << 1]; inline int C(int x, int y) { if (x < y) return 0; return (ll)fac[x] * inv[y] % mod * inv[x - y] % mod; } inline void AddEdge(int u, int v) { edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++; edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++; } void Dfs1(int u, int ff) { int e, v; size[u] = f[u] = 1; for (e = first[u]; ~e; e = edge[e].next) if ((v = edge[e].to) ^ ff) { Dfs1(v, u); f[u] = (ll)f[u] * C(size[u] + size[v] - 1, size[v]) % mod * f[v] % mod; size[u] += size[v]; } } void Dfs2(int u, int ff) { int e, v; Inc(ans, f[u]); for (e = first[u]; ~e; e = edge[e].next) if ((v = edge[e].to) ^ ff) { f[u] = (ll)f[u] * Pow((ll)C(size[u] - 1, size[v]) * f[v] % mod, mod - 2) % mod; size[u] -= size[v], size[v] += size[u]; f[v] = (ll)f[v] * C(size[v] - 1, size[u]) % mod * f[u] % mod; Dfs2(v, u); f[v] = (ll)f[v] * Pow((ll)C(size[v] - 1, size[u]) * f[u] % mod, mod - 2) % mod; size[v] -= size[u], size[u] += size[v]; f[u] = (ll)f[u] * C(size[u] - 1, size[v]) % mod * f[v] % mod; } } int main() { int i, u, v; memset(first, -1, sizeof(first)); scanf("%d", &n); for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u, v); fac[0] = fac[1] = inv[0] = inv[1] = 1; for (i = 2; i <= n; ++i) inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod; for (i = 2; i <= n; ++i) fac[i] = (ll)fac[i - 1] * i % mod, inv[i] = (ll)inv[i] * inv[i - 1] % mod; Dfs1(1, 0), Dfs2(1, 0); printf("%d\n", ans); return 0; }
枚舉最終的牌和第一種的數目
\[\sum_{i=0}^{S}\sum_{j=l}^{r}\binom{n+j-1}{j}\binom{m+i-j-1}{i-j}\]
運用交換求和順序以及組合恆等式能夠獲得
\[\sum_{i=l}^{r}\binom{n+i-1}{n-1}\binom{S-i+m}{m}\]
考慮求
\[\sum_{i=0}^{x}\binom{n+i-1}{n-1}\binom{S-i+m}{m}\]
能夠當作是枚舉一個點 \((i,n-1),i\in [0,x]\) 做爲中轉站,從 \((0,0)\) 到 \((i,n-1)\) 再到 \((i,n)\) 再到 \((S,n+m)\) 的格路問題。
也就是 \((0,0)\) 到 \((S,n+m)\) 必須通過端點爲 \((0,n),(x,n)\) 的線段。
這個能夠用總方案數減去通過 \((x,i)\) 和 \((x+1,i)\) 之間的邊的方案數,其中 \(i\in[1,n-1]\)
注意這裏是枚舉 \(n\),因此能夠直接算。code
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(2e7 + 5); const int mod(998244353); inline void Inc(int &x, const int y) { x = x + y >= mod ? x + y - mod : x + y; } inline void Dec(int &x, const int y) { x = x - y < 0 ? x - y + mod : x - y; } inline int Add(const int x, const int y) { return x + y >= mod ? x + y - mod : x + y; } inline int Sub(const int x, const int y) { return x - y < 0 ? x - y + mod : x - y; } inline int Pow(ll x, int y) { ll ret = 1; for (; y; y >>= 1, x = x * x % mod) if (y & 1) ret = ret * x % mod; return ret; } int n, m, s, l, r, f[maxn], g[maxn], inv[maxn]; inline int Calc(int x) { int i, ret = 0, y = s - x - 1; if (y < 0) return 0; f[0] = g[0] = 1; for (i = 1; i < n; ++i) f[i] = (ll)f[i - 1] * inv[i] % mod * (x + i) % mod; for (i = 1; i <= m + n; ++i) g[i] = (ll)g[i - 1] * inv[i] % mod * (y + i) % mod; for (i = 0; i < n; ++i) Dec(ret, (ll)f[i] * g[m + n - i] % mod); return ret; } int main() { int i; scanf("%d%d%d%d%d", &n, &m, &s, &l, &r); inv[0] = inv[1] = 1; for (i = 2; i <= n + m; ++i) inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod; printf("%d\n", Sub(Calc(r), Calc(l - 1))); return 0; }
實際就是仙人掌上的全部路徑的總長度對 \(Q\) 取模的值。
創建圓方樹,樹 \(dp\),處理出每一個點子樹內到它的路徑數目。
樹邊貢獻直接算,環邊貢獻都是同樣的,能夠考慮枚舉端點,也很好算。
兩遍樹 \(dp\) 便可。ci
主要代碼:頭文件太長了get
int mod; inline void inc(int &x, const int y) { x = x + y >= mod ? x + y - mod : x + y; } inline void dec(int &x, const int y) { x = x - y < 0 ? x - y + mod : x - y; } inline int add(const int x, const int y) { return x + y >= mod ? x + y - mod : x + y; } inline int sub(const int x, const int y) { return x - y < 0 ? x - y + mod : x - y; } inline int fpow(ll x, int y) { ll ret = 1; for (; y; y >>= 1, x = x * x % mod) if (y & 1) ret = ret * x % mod; return ret; } const int maxn(2e5 + 5); int n, m, tot, dfn[maxn], low[maxn], idx, sta[maxn], top, ans, bel[maxn]; int sum[maxn], fa[maxn], deep[maxn], type[maxn], cir[maxn], f[maxn]; vii graph[maxn]; vi tree[maxn]; inline void addgraph(int u, int v, int w) { graph[u].pb(mp(v, w)), graph[v].pb(mp(u, w)); } inline void addtree(int u, int v) { tree[u].pb(v), tree[v].pb(u); } void dfs(int u) { int v, s; dfn[u] = low[u] = ++idx, sta[++top] = u; for (auto cur : graph[u]) if (!dfn[v = cur.first]) { fa[v] = u, deep[v] = add(deep[u], cur.second); dfs(v), cmin(low[u], low[v]); if (low[v] >= dfn[u]) { ++tot, s = 0; do { ++s, addtree(tot, sta[top--]); bel[sta[top + 1]] = tot; } while (sta[top + 1] ^ v); addtree(tot, u); if (s == 1) type[tot] = 1, sum[tot] = cur.second; } } else { cmin(low[u], dfn[v]); if (low[v] == dfn[u]) sum[bel[v]] = add(cur.second, sub(deep[v], deep[u])); } } void dfs1(int u, int ff) { int val = type[u] ? 1 : 2; f[u] = u <= n; for (int v : tree[u]) if (v ^ ff) dfs1(v, u), inc(f[u], (ll)f[v] * val % mod); } void dfs2(int u, int ff) { int val = type[u] ? 1 : 2, ret = 0, s = 0; if (u > n) { for (int v : tree[u]) inc(s, (ll)ret * f[v] % mod), inc(ret, f[v]); inc(ans, (ll)s * sum[u] % mod); } for (int v : tree[u]) if (v ^ ff) { dec(f[u], (ll)f[v] * val % mod); inc(f[v], (ll)f[u] * (type[v] ? 1 : 2) % mod); dfs2(v, u); dec(f[v], (ll)f[u] * (type[v] ? 1 : 2) % mod); inc(f[u], (ll)f[v] * val % mod); } } int main() { int i, u, v, w; read(n, m, mod), tot = n; for (i = 1; i <= n; ++i) type[i] = 1; for (i = 1; i <= m; ++i) read(u, v, w), addgraph(u, v, w); dfs(1), dfs1(1, 0), dfs2(1, 0), print(ans); return 0; }
若是咱們可以構造一個多項式 \(H(x)=\prod_{i有二次剩餘}(x−i)^k\),那麼再將該多項式與 \(F(x)\) 取 \(Gcd\) 能夠獲得答案多項式。
二次剩餘有一個判斷式 \(x^{\frac{p−1}{2}}−1\equiv 0(mod~p)\)。
因此 \(x^{\frac{p−1}{2}}−1=\prod_{i有二次剩餘}(x-i)(mod~p)\)
只須要先將 \((x^{\frac{p−1}{2}}−1)^k\) 對 \(F(x)\) 取模,接下來兩個多項式的次數就都是 \(O(n)\) 級別的。
能夠利用快速冪算出 \(x^{\frac{p−1}{2}}\) 和 \((x^{\frac{p−1}{2}}−1)^k\)。it
主要代碼:io
Poly Gcd(Poly x, Poly y) { if (!y.size()) return x; Poly z = x % y; while (z.size() && !z[z.size() - 1]) z.pop_back(); return Gcd(y, z); } int n, k; Poly f, g, pw; int main() { int i, x, inv; scanf("%d%d", &n, &k), f.resize(n + 1); for (i = 0; i <= n; ++i) scanf("%d", &f[i]); g.resize(2), g[1] = 1, pw.resize(1), pw[0] = 1; for (x = (mod - 1) >> 1; x; g = g * g % f, x >>= 1) if (x & 1) pw = pw * g % f; Dec(pw[0], 1), g.resize(1), g[0] = 1; for (x = k; x; pw = pw * pw % f, x >>= 1) if (x & 1) g = g * pw % f; g = Gcd(f, g); printf("%d\n", x = (int)g.size() - 1); inv = Pow(g[x], mod - 2), g = g * inv; for (i = 0; i <= x; ++i) printf("%d ", g[i]); return puts(""), 0; }