控制面板
1、ZJOI2012 灾难
TAG:拓扑排序+倍增LCA
状态:100%
2、巡防
TAG:树上最远点对DP做法
状态:90%
3、完美代价
TAG:贪心
状态:100%
4、cards
TAG:未知
状态:100%
5、set
TAG:动态规划
状态:100%
6、chessboard
TAG:贪心
状态:75%
7、HCN
TAG:搜索
状态:20%
8、seq
TAG:动态规划
状态:100%
1、ZJOI2012 灾难
主体思路:求出拓扑序,对于每个节点根据联通关系重新构建一棵树,直接用dep数组体现。根据这棵树直接求出以每个节点为根节点的子树大小,即答案。中间用到倍增LCA来求得这棵树。
首先我们自己新建一个超级生产者0号节点,所有生产者都以这个超级生产者为食物。 考虑在所有生物中建立这样一个结构: 这个结构是一颗树,一个节点代表一种生物,树上一个节点满足这个灭绝会且仅会导致以它 为根的子树灭绝。 如果我们能够建立这样一个结构,那么每个生物对应的答案可以一边 dfs 统计子树大小就得出。
下面就介绍如何建立这样的结构: 首先,把所有的点按照从猎物到捕食者的顺序拓扑排序。然后依次考虑每一个生物 p,假设 在这之前已经建好了拓扑排序顺序在 p 之前的所有生物组成的上面描述的树结构。假设 p 的事物有 k 种,分别是 food[1]…food[k](由于拓扑排序,这些点都已经在树结构中)。那么 只有 food[1]…food[k]这 k 个点的 lca 到根的路径上的点会导致 p 灭绝。于是,就可以把 p 作 为 food[1]…food[k]这 k 个点的 lca 的儿子。 具体实现上,lca 用倍增维护即可,每次新加一个点,都可以一遍倍增把新加的点的倍增数 组得到。
1 #include <cstdio>
2 #include <algorithm>
3 #include <vector>
4 using namespace std;
5
6 #define MAXN 70005
7 #define pb push_back
8
9 int n, x, list[MAXN], f[MAXN][16], dep[MAXN], ans[MAXN], cnt[MAXN], tot;
10
11 vector <int> edge[MAXN], edge2[MAXN];
12
13 int LCA(int x, int y)
14 {
15 int o;
16 if (dep[x] < dep[y]) swap(x, y);
17 for (o = 0; (1 << o) <= dep[x]; o++); o--;
18 for (int i = o; i >= 0; i--)
19 if (dep[x] - (1 << i) >= dep[y]) x = f[x][i];
20 if (x == y) return x;
21 for (int i = o; i >= 0; i--)
22 if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
23 return f[x][0];
24 }
25
26 int main()
27 {
28 freopen("catas.in", "r", stdin);
29 freopen("catas.out", "w", stdout);
30 scanf("%d", &n);
31 for (int i = 1; i <= n; i++)
32 {
33 int lf = 1;
34 scanf("%d", &x);
35 while (x) edge[i].pb(x), edge2[x].pb(i), scanf("%d", &x), lf = 0;
36 if (lf) edge[i].pb(0), edge2[0].pb(i);
37 }
38 for (int i = 1; i <= n; i++) cnt[i] = edge[i].size();
39 for (int i = 0; i <= n; i++)
40 {
41 int o = list[i];
42 for (int x = 0; x < edge2[o].size(); x++)
43 {
44 int v = edge2[o][x];
45 if (!--cnt[v]) list[++tot] = v;
46 }
47 }
48 for (int i = 1; i <= n; i++)
49 {
50 int o = list[i], lca = -1;
51 for (int x = 0; x < edge[o].size(); x++)
52 {
53 int v = edge[o][x];
54 lca = lca == -1 ? v : LCA(lca, v);
55 }
56 dep[o] = dep[lca] + 1, f[o][0] = lca;
57 for (int j = 1; j <= 15; j++) f[o][j] = f[f[o][j - 1]][j - 1];
58 }
59 for (int i = 0; i <= n; i++) ans[i] = 1;
60 for (int i = n; i >= 0; i--) ans[f[list[i]][0]] += ans[list[i]];
61 for (int i = 1; i <= n; i++) printf("%d\n", ans[i] - 1);
62 return 0;
63 }
2、巡防
首先看如果要求从某村庄出发访问所有的村庄最后还要回来 那答案显然是所有边权之 和乘以 2(每条边都是一去一回) 现在不要求回来的话就是省掉了从某个点回到起点的这么条路径,显然这个路径越长越 靠谱,所以从某点出发的答案就是边权和乘 2 减去这个点到它最远点的距离。 然后就是树上的最远点对。这就化归到了一个经典模型上。
1 #include <cstdio>
2 #include <cstdlib>
3 #define MAXN 100005
4
5 int max(int a, int b) { return a > b ? a : b; }
6
7 struct Edge { int v, next, w; } edge[MAXN << 1];
8
9 int now, h[MAXN], n, u, v, w, dis[MAXN], vis[MAXN], maxw, maxp, f[MAXN], ans, sum, get[MAXN];
10
11 void addEdge(int u, int v, int w) { now++, edge[now] = (Edge) {v, h[u], w}, h[u] = now; }
12
13 void DFS(int o, int w)
14 {
15 if (w > maxw) maxw = w, maxp = o;
16 for (int x = h[o]; x; x = edge[x].next)
17 {
18 int v = edge[x].v;
19 if (!vis[v]) vis[v] = 1, get[v] = 1, DFS(v, w + edge[x].w), vis[v] = 0;
20 }
21 }
22
23 void DFS2(int o, int w)
24 {
25 dis[o] = max(dis[o], w);
26 if (w > maxw) maxw = w, maxp = o;
27 for (int x = h[o]; x; x = edge[x].next)
28 {
29 int v = edge[x].v;
30 if (!vis[v]) vis[v] = 1, DFS2(v, w + edge[x].w), vis[v] = 0;
31 }
32 }
33
34 int main()
35 {
36 freopen("path.in", "r", stdin);
37 freopen("path.out", "w", stdout);
38 scanf("%d", &n);
39 for (int i = 1; i <= n - 1; i++)
40 scanf("%d %d %d", &u, &v, &w), addEdge(u, v, w), addEdge(v, u, w), sum += w << 1;
41 for (int i = 1; i <= n; i++) scanf("%d", &f[i]);
42 for (int i = 1; i <= n; i++) if (f[i]) { get[i] = 1, DFS(i, 0); break; }
43 for (int i = 1; i <= n; i++) if (!get[i]) printf("-1"), exit(0);
44 DFS2(maxp, 0), DFS2(maxp, 0);
45 for (int i = 1; i <= n; i++) ans = (dis[i] > ans && f[i]) ? dis[i] : ans;
46 printf("%d", sum - ans);
47 return 0;
48 }
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #define MAXN 200005
5 using namespace std;
6 int n;
7 int totaledge,point[MAXN],v[MAXN],w[MAXN],next[MAXN];
8 int f[MAXN][2];
9 int g[MAXN][2];
10 int ans[MAXN];
11 void addedge(int x,int y,int z){
12 totaledge++;
13 v[totaledge] = y;
14 w[totaledge] = z;
15 next[totaledge] = point[x];
16 point[x] = totaledge;
17 }
18 void dfs1(int fa, int x){
19 int i,j;
20 for (i=point[x];i;i=next[i]){
21 if (v[i] == fa) continue;
22 dfs1(x, v[i]);
23 j = f[v[i]][0] + w[i];
24 if (j>f[x][0]){
25 f[x][1] = f[x][0];
26 g[x][1] = g[x][1];
27 f[x][0] = j;
28 g[x][0] = v[i];
29 }
30 else if (j>f[x][1]){
31 f[x][1] = j;
32 g[x][1] = v[i];
33 }
34 }
35 }
36 void dfs2(int fa, int x,int y){
37 int i,j;
38 ans[x] = max(f[x][0],y);
39 for (i=point[x];i;i=next[i]){
40 if (v[i] == fa) continue;
41 if (g[x][0]!=v[i]) dfs2(x, v[i],max(y,f[x][0])+w[i]);
42 else dfs2(x, v[i],max(y,f[x][1])+w[i]);
43 }
44 }
45 int d[MAXN];
46 char str[20];
47 int main(){
48 int i,x,y,z, t, ri;
49 // for (ri = 0; ri < 30; ri++){
50 // sprintf(str, "%d.in", ri);
51 freopen("path.in", "r", stdin);
52 // sprintf(str, "%d.out", ri);
53 freopen("path.out", "w", stdout);
54 scanf("%d",&n);
55 memset(point,0,sizeof(point));
56 totaledge = t = 0;
57 for (i=2;i<=n;i++){
58 scanf("%d%d%d",&x,&y, &z);
59 addedge(x,y,z);
60 addedge(y,x,z);
61 t += z + z;
62 }
63 z = 0;
64 for (i = 1; i <= n; i++){
65 scanf("%d", &d[i]);
66 z += d[i];
67 }
68 if (z == 0){
69 printf("-1\n");
70 return 0;
71 }
72 dfs1(0, 1);
73 dfs2(0, 1, 0);
74 z = 0;
75 for (i=1;i<=n;i++){
76 if (d[i]) z = max(z, ans[i]);
77 }
78 printf("%d\n", t - z);
79 // }
80 return 0;
81 }
3、完美代价
注意到这个问题可以这样考虑: 假设相同字符之间也是有区别的。那么字符串可以看做一个排列。如果答案是已知的一 个排列 P,则任务就是求从 (1,2,...,n) 变换到排列 P 需要多少次操作。
很明显,最优的方案要求每次使逆序对个数 +1 。很明显,一种最优的方法就是一开始就 将排列的第一个位置和最后一个位置放好,之后再对剩下的部分做变换。那么相对应的,也 有一种方法是最后才将排列的第一个位置和最后一个位置弄好。考虑使用这种方法。 假设现在要处理字符串的第一个字符和最后一个字符,他们分别为 A 和 B,并且我们用 C 来替代。由于 C 一定要移动到和 A, B 相邻的位置,所以如下图:
+-------+
| |
| |
AC ... CB
明显,如果 C ≠ A,B ,则交换 AC 和 CB 后方案是不合法的,因此 C 一定是 A,B 中的 一个。
那么再回到一开始的先处理头尾的情况。容易知道 C 要和 A, B 相等,因此我们只需要 找到离 A 最近的 B 以及离 B 最近的 A,判断哪个更近即可。
1 #include <cstdio>
2 #include <cstdlib>
3 #include <cstring>
4 #include <algorithm>
5 using namespace std;
6
7 char s[10010];
8 int n, cnt;
9
10 int main() {
11 freopen("reference.in","r",stdin); freopen("reference.out","w",stdout);
12 scanf("%d", &n);
13 scanf("%s", s + 1);
14
15 int x = 0, y = n + 1;
16 while (++x < --y) {
17 if (s[x] == s[y])
18 continue;
19 int nx = x + 1, ny = y - 1;
20 while (s[nx] != s[y])
21 ++nx;
22 while (s[ny] != s[x])
23 --ny;
24 if (nx == y && ny == x) {
25 printf("Impossible");
26 return 0;
27 }
28 if (nx - x <= y - ny && nx != y)
29 for (int i = nx; i > x; --i)
30 swap(s[i], s[i - 1]), ++cnt;
31 else
32 for (int i = ny; i < y; ++i)
33 swap(s[i], s[i + 1]), ++cnt;
34 }
35 printf("%d\n", cnt);
36 }
1 #include <cstdio>
2 #define MAXN 8005
3
4 int n, tot[30], totx, x;
5 char ch[MAXN];
6
7 int work()
8 {
9 int res = 0;
10 for (int i = 0; i <= (n >> 1); i++)
11 if (ch[i] == x)
12 {
13 for (int j = i; j < n - i - 1; j++)
14 if (ch[n - i - 1] == ch[j])
15 {
16 res += j - i;
17 for (int k = j; k > i; k--) ch[k] = ch[k - 1];
18 ch[i] = ch[n - i - 1];
19 break;
20 }
21 }
22 else
23 {
24 for (int j = n - i - 1; j >= i; j--)
25 if (ch[i] == ch[j])
26 {
27 res += n - i - 1 - j;
28 for (int k = j; k < n - i - 1; k++) ch[k] = ch[k + 1];
29 ch[n - i - 1] = ch[i];
30 break;
31 }
32 }
33 return res;
34 }
35
36 int main()
37 {
38 freopen("reference.in", "r", stdin);
39 freopen("reference.out", "w", stdout);
40 scanf("%d %s", &n, ch);
41 for (int i = 0; i <= n - 1; i++) tot[ch[i] - 'a']++;
42 for (int i = 0; i <= 25; i++) if (tot[i] % 2) totx++, x = i + 'a';
43 if (totx >= 2) printf("Impossible"); else printf("%d", work());
44 return 0;
45 }
4、cards
假设最后 xxxxxx..xxxxxx 被分成了 y 块 那么要在其中找 y-1 个位置插入 o 然后我们发现这 y-1 个位置会决定减去的分数 而在 y-1 个位置怎么放 o 会决定加上的分数 这两者是独立的
考虑怎么找这 y-1 个位置 显然是越平均越好 比如说将 4 分成两份 1+3*3>2*2+2*2
在 y-1 个位置怎么放呢 显然是 y-2 个位置中放一个 o 剩下一个位置放剩余的 o 和放 x 的原理是一样的
然后需要注意下 y=1 的情况
枚举 y 即可
1 #include <cstdio>
2 #define INF 1ll << 60
3
4 typedef long long ll;
5
6 ll a, b, ans = -INF, x;
7
8 ll get(ll o)
9 {
10 ll s = b / (o + 1), v = b % (o + 1);
11 ll f1 = v * (s + 1) * (s + 1) + (o + 1 - v) * s * s, f2 = o ? (a - o + 1) * (a - o + 1) + o - 1 : (a - o) * (a - o) + o;
12 return f2 - f1;
13 }
14
15 int main()
16 {
17 freopen("cards.in", "r", stdin);
18 freopen("cards.out", "w", stdout);
19 scanf("%d %d", &a, &b);
20 for (ll i = 0; i <= a; i++)
21 {
22 ll o = get(i);
23 if (o > ans) ans = o, x = i;
24 }
25 printf("%I64d\n", ans);
26 ll s = b / (x + 1), v = b % (x + 1);
27 if (!x)
28 {
29 for (ll i = 1; i <= b; i++) printf("x");
30 for (ll i = 1; i <= a; i++) printf("o");
31 }
32 else
33 {
34 for (ll i = 1; i <= v; i++)
35 {
36 for (ll j = 1; j <= s + 1; j++) printf("x");
37 printf("o");
38 }
39 for (ll i = 1; i <= x - v; i++)
40 {
41 for (ll j = 1; j <= s; j++) printf("x");
42 printf("o");
43 }
44 for (ll i = 1; i <= a - x; i++) printf("o");
45 for (ll i = 1; i <= s; i++) printf("x");
46 }
47 return 0;
48 }
5、set
注意到我们计数的状态有对成型,即:一个A胜利的局面恰好唯一对应一个B胜利的局面(双射为交换双方状态)。
那么,我们只需要考虑AB平局的状态,用总状态数减去平局状态并除以2就能得到A胜利的状态数。
由于异或有自反性,所以AB平局的局面两者得到的权值的异或值为0.
以f[i][j]表示第i个数,现在两者得到的权值的异或值为j的方案数:
f[i][j] = f[i - 1][j] + f[i - 1][j ^ a[i]] + f[i - 1][j ^ a[i]]
则答案为1 / 2 * (3的n次方 - f[n][0])。
1 #include <cstdio>
2 #include <algorithm>
3 using namespace std;
4
5 #define ll long long
6 #define FOR( A, B, C ) for ( int A = B, _end_ = C; A <= _end_; A++ )
7
8 int f[ 4096 ][ 4096 ], n, a[ 4096 ], P = 1998585857;
9
10 int fpm( int F, int FF, int P ) {
11 int ans = 1;
12 for ( ; FF; FF >>= 1, F = (ll)F * F % P )
13 if ( FF & 1 ) ans = (ll)ans * F % P;
14 return ans;
15 }
16
17 int main() {
18 freopen( "set&set.in", "r", stdin );
19 freopen( "set&set.out", "w", stdout );
20
21 scanf( "%d", &n );
22 FOR ( i, 1, n ) { scanf( "%d", &a[ i ] ); }
23
24 f[ 0 ][ 0 ] = 1;
25 FOR ( i, 1, n ) {
26 FOR ( j, 0, 4095 ) {
27 f[ i ][ j ] = ( f[ i - 1 ][ j ] + ( (ll)f[ i - 1 ][ j ^ a[ i ] ] << 1 ) ) % P;
28 }
29 }
30
31 int ans = ( (ll)fpm( 3, n, P ) - f[ n ][ 0 ] + P ) % P; ans = (ll)ans * fpm( 2, P - 2, P ) % P;
32
33 printf( "%d\n", ans );
34 }
6、chessboard
其实这个问题可以用贪心能解决,以横轴为例,假设扫描到了i,将左端点<=i的区间都加入一个集合,然后在已经加入的区间集合中选取一个右端点最小的区间来作为i的匹配区间即可。用堆优化或者set。
1 #include <cstdio>
2 #include <cstring>
3 #include <set>
4 using namespace std;
5
6 #define MAXN 100005
7
8 int n, a[MAXN], b[MAXN], c[MAXN], d[MAXN], ansx[MAXN], ansy[MAXN], h[MAXN], next[MAXN], md;
9
10 struct cmp
11 {
12 bool operator () (int x, int y)
13 {
14 return md ? (d[x] < d[y] || (d[x] == d[y] && x < y)) : (c[x] < c[y] || (c[x] == c[y] && x < y));
15 }
16 };
17
18 set <int, cmp> st;
19
20 bool work1()
21 {
22 int get = 0; md = 0;
23 st.clear(), memset(h, 0, sizeof(h));
24 for (int i = 1; i <= n; i++)
25 next[i] = h[a[i]], h[a[i]] = i;
26 for (int i = 1; i <= n; i++)
27 {
28 for (int x = h[i]; x; x = next[x]) st.insert(x);
29 while (!st.empty())
30 {
31 int o = *st.begin(); st.erase(o);
32 if (c[o] < i) continue;
33 ansx[o] = i, get = 1;
34 break;
35 }
36 if (!get) return 0;
37 }
38 return 1;
39 }
40
41 bool work2()
42 {
43 int get = 0; md = 1;
44 st.clear(), memset(h, 0, sizeof(h));
45 for (int i = 1; i <= n; i++)
46 next[i] = h[b[i]], h[b[i]] = i;
47 for (int i = 1; i <= n; i++)
48 {
49 for (int x = h[i]; x; x = next[x]) st.insert(x);
50 while (!st.empty())
51 {
52 int o = *st.begin(); st.erase(o);
53 if (d[o] < i) continue;
54 ansy[o] = i, get = 1;
55 break;
56 }
57 if (!get) return 0;
58 }
59 return 1;
60 }
61
62 int main()
63 {
64 freopen("chessboard.in", "r", stdin);
65 freopen("chessboard.out", "w", stdout);
66 scanf("%d", &n);
67 for (int i = 1; i <= n; i++)
68 scanf("%d %d %d %d", &a[i], &b[i], &c[i], &d[i]);
69 if (work1() && work2())
70 for (int i = 1; i <= n; i++) printf("%d %d\n", ansx[i], ansy[i]);
71 else printf("%d", -1);
72 return 0;
73 }
7、HCN
大搜索题。首先,对于一个数a,由唯一分解定律一定可以分为a = p1 ^ c1 * p2 ^ c2 * ...* pn ^ cn,且其因子个数为。第一步,对于一组给定的c,显然我们应该把较大的ci分给较小的质数,这样可以得到更小的a。从而应该把c由大到小分配给前n个质数。
只是这样写就能解决n <= 10 ^ 18的部分了。接下来的部分就要写高精度了。
为了降低计算量,我们考虑加入最优化剪枝:
1、当c1确定时,我们在考虑当前第i个素数的指数时,存在一个上界c1 / ki,其中ki表示最大的满足2 ^ ki <= pri[i]的数,当ci比其更大时,不如ci -= 1,c1 += ki。
2、同样地方法,我们也能得到它的一个上界(c1 - 2 * ki - 1) / (1 + ki),表示ci比其更小时,不如c1 -= ki,ci += 1
3、以上两个剪枝的关键都在于没有办法给2进行剪枝,所以我们可以考虑如何限制住c1.我们可以考虑用满足来进行对一个素数的剪枝。令ti表示最大的满足pri[i]^ti <= pri[n + 1]的数,当ci > 2 * ti时,不如把ci -= ti,c[n + 1] += 1。
呕。
1 #include <cstdio>
2 #include <cstring>
3
4 #define MAX 30
5 #define MAXX 205
6 #define LEN 100000000
7
8 typedef long long ll;
9
10 int max1(int a, int b) { return a > b ? a : b; }
11
12 int min1(int a, int b) { return a < b ? a : b; }
13
14 ll max;
15
16 int pri[MAXX], ptop, top, s[MAXX], dig = LEN, q[MAXX], k[MAXX];
17
18 struct ubInt
19 {
20 ll num[MAX + 1];
21 int fir;
22
23 void init(int x) { num[fir = MAX] = x; }
24
25 void clear() { for (int i = fir; i <= MAX; i++) num[i] = 0; fir = MAX; }
26
27 void exceed()
28 {
29 int i = MAX, j = 0;
30 for (; i >= fir || j; i--)
31 {
32 num[i] += j, j = 0;
33 if (num[i] >= dig) j = num[i] / dig, num[i] %= dig;
34 }
35 fir = i + 1;
36 }
37
38 void operator *= (const int x)
39 {
40 for (int i = fir; i <= MAX; i++) num[i] *= x;
41 exceed();
42 }
43
44 void operator = (const ubInt &x)
45 {
46 clear();
47 for (int i = x.fir; i <= MAX; i++) num[i] = x.num[i];
48 fir = x.fir;
49 }
50
51 void read()
52 {
53 char ch[MAXX]; int l;
54 scanf("%s", ch), l = strlen(ch);
55 int j = 1; fir = MAX;
56 for (int i = l - 1; i >= 0; i--)
57 {
58 num[fir] += (ch[i] - '0') * j, j *= 10;
59 if (j == dig) j = 1, fir--;
60 }
61 if (j == 1) fir++;
62 }
63
64 void print()
65 {
66 printf("%I64d", num[fir]);
67 for (int i = fir + 1; i <= MAX; i++) printf("%08I64d", num[i]);
68 printf("\n");
69 }
70 };
71
72 ubInt ans, n, now[MAXX + 10];
73
74 int operator < (const ubInt &a, const ubInt &b)
75 {
76 if (a.fir != b.fir) return a.fir > b.fir;
77 for (int i = a.fir; i <= MAX; i++)
78 if (a.num[i] != b.num[i]) return a.num[i] < b.num[i];
79 return 0;
80 }
81
82 void init() {
83 #define MMM 300
84 int t[MMM + 10];
85 max = 1, ans.init(1);
86 for (int i = 1; i <= MAX; i++) now[i].fir = MAX;
87 now[1].num[MAX] = 1;
88 for (int i = 2; i <= MMM; i++) t[i] = 0;
89 for (int i = 2; i <= MMM; i++)
90 if (!t[i])
91 {
92 pri[++ptop] = i;
93 for (int j = 2; j * pri[ptop] <= MMM; j++) t[j * pri[ptop]] = 1;
94 }
95 ubInt e; e.fir = 0, e.clear(), e.init(1);
96 for (int i = 1; i <= ptop; i++)
97 {
98 e *= pri[i];
99 if (n < e) { top = i - 1; break; }
100 }
101 for (int i = 1; i <= top; i++)
102 {
103 int tmp = 1;
104 for (int j = 0; j <= 100; j++)
105 {
106 if (tmp > pri[top]) { s[i] = j - 1; break; }
107 tmp *= pri[i];
108 }
109 }
110 for (int i = 1; i <= top; i++)
111 {
112 int tmp = 1;
113 for (int j = 0; j <= 100; j++)
114 {
115 if (tmp > pri[i]) { k[i] = j - 1; break; }
116 tmp <<= 1;
117 }
118 }
119 }
120
121 void brute(int v, ll get, int r3)
122 {
123 if (n < now[v]) return;
124 else if (get > max || (get == max && now[v] < ans)) max = get, ans = now[v];
125 if (v > top) return;
126 int l = 1, r1 = 1 << 30, r2;
127 if (v != 1) l = (q[1] - (k[v] << 1) - 1) / (1 + k[v]) + 1, r1 = q[1] / k[v];
128 r2 = s[v] << 1 | 1;
129 now[v + 1] = now[v];
130 for (int i = 1; i <= max1(l, 1) - 1; i++) now[v + 1] *= pri[v];
131 for (int i = max1(l, 1); i <= min1(min1(r1, r2), r3); i++)
132 now[v + 1] *= pri[v], q[v] = i, brute(v + 1, get * (i + 1), i);
133 }
134
135 int main()
136 {
137 freopen("HCN.in", "r", stdin);
138 freopen("HCN.out", "w", stdout);
139 n.read(), init(), brute(1, 1, 100), ans.print();
140 return 0;
141 }
8、seq
考虑已经有了一个子序列 我现在要在后面加入一个数 a[i] 如果能加说明不存在二元组(s,t)满足 a[s]<a[t]<a[i] 二元组有很多我们需要关心的其实只是最小的 a[t]
那么加进去一个数字以后最小的 a[t]可能发生改变 那么如何判断加进去的 a[i]能否成为最小的 a[t]呢 只需要知道没加进 a[i]时的子序列的最小值
那么 dp 的思路就建立了
令 f[i][j][l]表示考虑了前 i 个数 子序列中最小值为 j 子序列中最小的 a[t]为 l
1 #include <cstdio>
2 #define MAXN 205
3 #define MOD 1000000007
4
5 int n, a[MAXN], f[MAXN][MAXN][MAXN], ans;
6
7 void upd(int &a, int b) { (a += b) %= MOD; }
8
9 int main()
10 {
11 freopen("seq.in", "r", stdin);
12 freopen("seq.out", "w", stdout);
13 scanf("%d", &n);
14 for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
15 f[0][n + 1][n + 1] = 1;
16 for (int i = 0; i < n; i++)
17 for (int j = 1; j <= n + 1; j++)
18 for (int l = 1; l <= n + 1; l++)
19 if (f[i][j][l])
20 {
21 upd(f[i + 1][j][l], f[i][j][l]);
22 if (a[i + 1] > l) continue;
23 if (a[i + 1] > j) upd(f[i + 1][j][a[i + 1]], f[i][j][l]);
24 if (a[i + 1] < j) upd(f[i + 1][a[i + 1]][l], f[i][j][l]);
25 }
26 for (int j = 1; j <= n; j++)
27 for(int l = 1; l <= n + 1; l++) upd(ans, f[n][j][l]);
28 printf("%d", ans);
29 return 0;
30 }
来源:https://www.cnblogs.com/jinkun113/p/4941252.html