今天的模拟也太毒瘤了……
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 }
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 }
正解现在看起来也不难:对于新加入的一条边(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 }
T3 polynomial
期望得分:0
实际得分:0
模拟能放到T3,那自然不可做。
30分手推还是gg了。题解看不懂。
明天我觉得应该能考数据结构吧。