2018.10.04模拟总结

今天的模拟也太毒瘤了……

 

T1 permutation

  期望得分:20

  实际得分:20  

  我刚开始是这么想的:T1嘛,应该不会太难,想想正解吧。本来想求出所有不合法的情况,然后用n!减一下。于是用dp,但发现这玩意是有后效性的,硬推了将近一个点儿,最终还是放弃了。只能20分全排列暴力了……

  正解完全没看懂,居然成了什么二分图的补图,然后还用什么卷积……弃疗了

20分的

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 12;
21 const ll mod = 998244353;
22 inline ll read()
23 {
24     ll ans = 0;
25     char ch = getchar(), last = ' ';
26     while(!isdigit(ch)) {last = ch; ch = getchar();}
27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
28     if(last == '-') ans = -ans;
29     return ans;
30 }
31 inline void write(ll x)
32 {
33     if(x < 0) x = -x, putchar('-');
34     if(x >= 10) write(x / 10);
35     putchar(x % 10 + '0');
36 }
37 
38 int n, k, a[maxn];
39 ll ans = 0;
40 
41 ll fac[maxn * 10000];
42 void work0()
43 {
44     fac[1] = 1;
45     for(int i = 2; i <= n; ++i) fac[i] = fac[i - 1] * i % mod;
46     write((fac[n] - fac[n - 1]) % mod); enter;
47 }
48 
49 int main()
50 {
51     freopen("permutation.in", "r", stdin);
52     freopen("permutation.out", "w", stdout);
53     n = read(); k = read();
54     if(n > 10) {work0(); return 0;}
55     for(rg int i = 1; i <= n; ++i) a[i] = i;
56     do
57     {
58         bool flg = 1;
59         for(rg int i = 1; i <= n; ++i) if(abs(a[i] - i) == k) {flg = 0; break;}
60         if(flg) ans++;
61     }while(next_permutation(a + 1, a + n + 1));
62     write(ans % mod); enter;
63     return 0;
64 }
View Code

T2 tree

  期望得分:60

  实际得分:55

  60分多好写啊!枚举每一个不在树上的边,删去他然后跑tarjan求桥。丢了5分是因为不在树上的边和树上的边构成了重边,tarjan的时候还要单独判断一下这条边是否是新加的。

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 3e5 + 5;
21 inline ll read()
22 {
23     ll ans = 0;
24     char ch = getchar(), last = ' ';
25     while(!isdigit(ch)) {last = ch; ch = getchar();}
26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
27     if(last == '-') ans = -ans;
28     return ans;
29 }
30 inline void write(ll x)
31 {
32     if(x < 0) x = -x, putchar('-');
33     if(x >= 10) write(x / 10);
34     putchar(x % 10 + '0');
35 }
36 
37 int n, m;
38 #define pr pair<int, int>
39 #define mp make_pair
40 vector<pr> v[maxn];
41 
42 ll ans = 0;
43 int dfn[maxn], low[maxn], cnt;
44 void tarjan(const int& now, const int& fa, const int& flg)
45 {
46     dfn[now] = low[now] = ++cnt;
47     for(int i = 0; i < (int)v[now].size(); ++i)
48     {
49         if(v[now][i].second == flg) continue;
50         int to = v[now][i].first;
51         if(!dfn[to])
52         {
53             tarjan(to, now, flg);
54             low[now] = min(low[now], low[to]);
55             if(low[to] > dfn[now]) ans++;
56         }
57         else if(to != fa || v[now][i].second) low[now] = min(low[now], dfn[to]);
58     }
59 }
60 inline void init()
61 {
62     for(int i = 1; i <= n; ++i) dfn[i] = low[i] = 0;
63     cnt = 0;
64 }
65 
66 int main()
67 {
68     freopen("tree.in", "r", stdin);
69     freopen("tree.out", "w", stdout);
70     n = read(); m = read();
71     for(int i = 1; i < n; ++i)
72     {
73         int x = read(), y = read();
74         v[x].push_back(mp(y, 0)); v[y].push_back(mp(x, 0));
75     }
76     for(int i = 1; i <= m; ++i)
77     {
78         int x = read(), y = read();
79         v[x].push_back(mp(y, i)); v[y].push_back(mp(x, i));
80     }
81     for(int i = 1; i <= m; ++i)
82     {
83         init();
84         for(int j = 1; j <= n; ++j) if(!dfn[j]) tarjan(j, 0, i);
85     }
86     write(ans); enter;
87     return 0;
88 }
View Code

  正解现在看起来也不难:对于新加入的一条边(x, y),对于原来树上的路径x -> y的所有边而言,必须要割掉这条新的边和自己,才能使整棵树不连通;而如果又有一条边(x, y),则这些路径上的边怎么割都割不掉了。所以总结一下:新加入一条边(x, y)相当于树上路径加1,最后判断这条边的值:如果是1,对答案的贡献就是1,;如果是0,贡献就是m;否则是0.

  链上修改可以用树剖,更优的解法是树上差分。时间复杂度取决于lca复杂度。

85分代码(不知为啥有三个点RE了,调了小半个下午没调出来)

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("")
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 3e5 + 5;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) last = ch, ch = getchar();
 26     while(isdigit(ch)) ans = ans * 10 + ch - '0', ch = getchar();
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) x = -x, putchar('-');
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36 
 37 void MYFILE()
 38 {
 39 #ifndef mrclr
 40     freopen("tree.in", "r", stdin);
 41     freopen("tree.out", "w", stdout);
 42 #endif
 43 }
 44 
 45 int n, m;
 46 struct Edge
 47 {
 48     int nxt, to;
 49 }e[maxn << 2];
 50 int head[maxn], ecnt = 0;
 51 void add(int x, int y)
 52 {
 53     e[++ecnt].to = y;
 54     e[ecnt].nxt = head[x];
 55     head[x] = ecnt;
 56 }
 57 
 58 int dep[maxn], dp[maxn][28];
 59 void dfs(int now, int fa)
 60 {
 61     for(int i = 1; i <= 25; ++i)
 62         dp[now][i] = dp[dp[now][i - 1]][i - 1];
 63     for(int i = head[now]; i; i = e[i].nxt)
 64     {
 65         if(e[i].to != fa)
 66         {
 67             dep[e[i].to] = dep[now] + 1;
 68             dp[e[i].to][0] = now;
 69             dfs(e[i].to, now);
 70         }
 71     }
 72 }
 73 int lca(int x, int y)
 74 {
 75     if(dep[x] < dep[y]) swap(x, y);
 76     for(int i = 25; i >= 0; --i)
 77         if(dep[dp[x][i]] >= dep[y]) x = dp[x][i];
 78     if(x == y) return x;
 79     for(int i = 25; i >= 0; --i)
 80         if(dp[x][i] != dp[y][i]) x = dp[x][i], y = dp[y][i];
 81     return dp[x][0];
 82 }
 83 
 84 int dif[maxn];
 85 void dfs2(int now, int fa)
 86 {
 87     for(int i = head[now]; i; i = e[i].nxt)
 88     {
 89         if(e[i].to != fa)
 90         {
 91             dfs2(e[i].to, now);
 92             dif[now] += dif[e[i].to];
 93         }
 94     }
 95 }
 96 
 97 int main()
 98 {
 99     MYFILE();
100     n = read();
101     m = read();
102     for(int i = 1; i < n; ++i)
103     {
104         int x = read(), y = read();
105         if(x == y) continue;
106         add(x, y); add(y, x);
107     }
108     dfs(1, 0);
109     for(int i = 1; i <= m; ++i)
110     {
111         int x = read(), y = read();
112         dif[x]++; dif[y]++; 
113         dif[lca(x, y)] -= 2;
114     }
115     dfs2(1, 0);
116     ll ans = 0;
117     for(rg int i = 1; i <= n; ++i)
118     {
119         ans += (dif[i] == 1);
120         ans += (dif[i] == 0) * m;
121     }
122     write(ans - m); enter;
123     return 0;
124 }
View Code

T3 polynomial

  期望得分:0

  实际得分:0

  模拟能放到T3,那自然不可做。

  30分手推还是gg了。题解看不懂。

明天我觉得应该能考数据结构吧。

原文地址:https://www.cnblogs.com/mrclr/p/9742380.html