3月自训 (1):10/12
A:
题意:每个人可以连边,最远连到第(i+k)%n个人,边权为这个人与另一个人连边距离,求生成一颗最大生成树的权值和是多少
题解:可以证明的是,我们每一个人都向接下来的第k个人连边,剩下的连第k-1个人,这样得到的边权和一定是最大的
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int main() { #ifndef ONLINE_JUDGE FIN #endif int n, k; cin >> n >> k; int g = __gcd(n, k); LL ans = 1LL * k * g * (n / g - 1) + 1LL * (g - 1) * (k - 1); cout << ans << endl; return 0; }
B:
题意:给你一串长度为n的数,这个数可以将后面的数挪到前面来,如果没有小于最开始的那个数的话就输出YES,否则输出NO
题解:如果后面有数字小于第一个数的话就肯定是NO了,这题的坑点就是如果前面很长一串都相同但是后面有一个比前面相同位置的数小的话也要输出NO,因为n是5e5,我们不可能检查每一个串,其实对于这个字符串,我们可以求出这个数的最小表示法的答案,如果这个字符串的最小表示法的第一个字符不是第一个的话就是NO了
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 1e6 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int n; char s[maxn]; int main() { #ifndef ONLINE_JUDGE FIN #endif scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) { s[i + n] = s[i]; } bool flag = 0; for(int i = 1; i <= n; i++) { if(s[i] < s[0]) { flag = 1; break; } } if(flag) { cout << "NO" << endl; } else { int i = 1, j = 2, k; while(i <= n && j <= n) { for(k = 0; k <= n && s[i + k] == s[j + k]; k++); if(k == n) break; if(s[i + k] > s[j + k]) { i = i + k + 1; if(i == j)i++; } else { j = j + k + 1; if(i == j) j++; } } int ans = min(i, j); if(ans != 1) cout << "NO" << endl; else cout << "YES" << endl; } return 0; }
C:
题意:给出n个数和一个限制条件b,为你这n个数有多少个数的因子个数恰好等b
题解:数的范围是1e12,我们可以先预处理出1e6内的素数,然后将输入的每一个数唯一分解,得到一个素因子和其幂次的一个映射。
设dp状态为dp[i][j]指的是从大数的第一个i素因子获得带有j个除数的方案数
设当前的幂为b时,除数的数量=b/(x+1);
转移就是:dp[pos][need]=dp[pos][need]+dp[pos+1][need/(i+1)];
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e6 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int v[maxn], prime[maxn]; int m; void xprime(int n) { memset(v, 0, sizeof(v)); m = 0; for(int i = 2; i <= n; i++) { if(v[i] == 0) { v[i] = i; prime[m++] = i; } for(int j = 1; j <= m; j++) { if(prime[j] > v[i] || prime[j] > n / i) break; v[i * prime[j]] = prime[j]; } } } set<int> st; map<LL, int> mp; void check(LL x) { //唯一分解 for(int i = 0; i < m && prime[i]*prime[i] <= x; i++) { if(x % prime[i] == 0) { int cnt = 0; while(x % prime[i] == 0) { //cout << prime[i] << endl; x /= prime[i]; cnt++; } mp[prime[i]] += cnt; //prime的cnt次方 } } if(x > 1) mp[x]++; //cout << x << endl; } vector<int> vec;//vec[i]存的是每一个素数的幂次项是多少 bool vis[3005][1005]; LL dp[3005][1005]; //dp[i][j]指的是从大数的第一个i素因子获得带有j个除数的方案数 //设当前的幂为b时,除数的数量=b/(x+1); LL solve(int pos, int need) { if(pos == vec.size()) { return need == 1; } if(vis[pos][need]) { return dp[pos][need]; } //printf("%d %d ", pos, need); vis[pos][need] = 1; for(int i = 0; i <= vec[pos]; i++) { //枚举幂次 if(need % (i + 1) == 0) { //dp[pos][need]=dp[pos][need]+dp[pos+1][need/(i+1)]; dp[pos][need] = (dp[pos][need] + solve(pos + 1, need / (i + 1))) % mod; } } return dp[pos][need]; } int main() { #ifndef ONLINE_JUDGE FIN #endif xprime(1000005); int n, m; scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) { LL x; scanf("%lld", &x); check(x);//将x唯一分解 } //map的键为素因子,值为个数 map<LL, int>::iterator it; for(it = mp.begin(); it != mp.end(); it++) { vec.push_back(it->second); } //从第0个位置开始 cout << solve(0, n) << endl; return 0; }
D:
题意:我们最多可以走n步,每一步可以走上下左右,问你从起点走到终点有多少种方法
题解:我们先计算出从起点到终点的距离len,如果len大于n,那么肯定是不能走的,否则的话我们走的方法数为(n-len)/2+1种方法
坑点,如果起点和终点是一样的话,我们的方法数是n/2
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int main() { #ifndef ONLINE_JUDGE FIN #endif LL rs, cs, rt, ct; LL n; scanf("%lld%lld%lld%lld%lld", &n, &rs, &cs, &rt, &ct); LL len = abs(ct - cs) + abs(rt - rs); LL ans = (n - len) / 2 + 1; if(len > n) ans = 0; else if(rs == rt && cs == ct) { ans = n / 2; } cout << ans << endl; return 0; }
E:
题意:给你一个长度为n的01串,0表示当天不需要工作,1表示当天需要工作,我初始时有体力值为k,如果连续工作时,我第一天需要耗费的体力值为1,第二天需要耗费的体力值为2,第三天许哟啊耗费的体力值为3,,,以此类推,问我们现在需要从这个01串中最少改变多少个1为0使得我们k个体力值够用
题解:记忆化搜索,我们记忆当我们从在第i个位置删去了j个工作日时所需要消耗的体力值,如果这个状态走过就不用走,那么复杂度就是O(ac)了(滑稽
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int n, m; int vis[505][505];//标记 在第i个位置 删去了j个后 所需要消耗的体力值 char str[maxn]; int dfs(int pos, int cnt) { if(cnt < 0 ) return INF; if(pos == n) return 0; // debug1(vis[pos][cnt]); if(~vis[pos][cnt]) return vis[pos][cnt]; if(str[pos] == '0') return dfs(pos + 1, cnt); vis[pos][cnt] = INF; int i; for(i = pos; i < n && str[i] == '1'; ++i) { vis[pos][cnt] = min(vis[pos][cnt], dfs(i + 1, cnt - 1) + (i - pos) * (i - pos + 1) / 2); if(vis[pos][cnt] == 0) return 0; } vis[pos][cnt] = min(vis[pos][cnt], dfs(i, cnt) + (i - pos) * (i - pos + 1) / 2); return vis[pos][cnt]; } int main() { #ifndef ONLINE_JUDGE FIN #endif memset(vis, -1, sizeof(vis)); scanf("%d%d%s", &n, &m, str); for(int i = 0; i <= n; i++) { if(dfs(0, i) <= m) { printf("%d ", i); break; } } return 0; }
F:
题意:有n个人,每个人如果有喜欢的数,那么他就只喜欢这些数,如果他有讨厌的数,那么他就喜欢除了这个数外的任何数,求有多少个数是这n个人都喜欢的
题解:map记录一下就行,如果没有只喜欢某一些数的人的话,我们就输出1e8-(所有人讨厌的数即可)
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; int dislike[maxn]; set<LL> s; bool flag1[maxn]; bool flag2[maxn]; map<LL, int> mp; int main() { #ifndef ONLINE_JUDGE FIN #endif int n; scanf("%d", &n); int cnt1 = 0, cnt2 = 0; for(int i = 1, op, cnt; i <= n; i++) { scanf("%d%d", &op, &cnt); if(op == 1) cnt1++; else cnt2++; LL x; for(int j = 0; j < cnt; j++) { scanf("%lld", &x); if(op == 1 && mp[x] != -1) { mp[x]++; } else { s.insert(x); mp[x] = -1; } } } int ans = 0; map<LL, int>::iterator it; for(it = mp.begin(); it != mp.end(); it++) { if(it->second == cnt1) { ans++; } } if(cnt1 == 0) { cout << (LL)( 1000000000000000000 - s.size() ) << endl; } else { cout << ans << endl; } }
G:
题意:在一条直线上有n辆车,每辆车都有自己的位置和速度,如果后面一辆车撞上前面一辆车时,后面一辆车的速度会变得和前面一辆车一样,问你什么时候不可能有车子相撞
题解:我们先将车按照pos的顺序从小到大排序,定义第一辆车为1,从n到1扫一遍,如果在第i个位置的车的速度小于我当前车的速度的话,我当前位置的的车的速度是一定会变成第i个位置的速度,否则的话,我当前位置的车是一定会被撞的,计算出被第i辆车撞的时间保存最大值即可
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 7777777; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; struct node { int pos, v; } a[maxn]; bool cmp(node a, node b) { return a.pos < b.pos; } int main() { #ifndef ONLINE_JUDGE FIN #endif int n; scanf("%d", &n); int minnv = INF; for(int i = 1; i <= n; i++) { scanf("%d%d", &a[i].pos, &a[i].v); } sort(a + 1, a + n + 1, cmp); int pos = n ; double ans = 0; for(int i = n - 1; i >= 0; i--) { if(a[i].v <= a[pos].v) { pos = i; } else { int len = a[pos].pos - a[i].pos; int v = a[i].v - a[pos].v; ans = max(ans, 1.0 * len / v); } } printf("%.6lf", ans); return 0; }
H:
题意:有一个密码箱,他有n个数字齿轮,每个齿轮是可以被转动的,有两个人玩起了这个游戏,现在有以下的游戏规则
1.每一轮游戏,这个人可以选择非0的一个齿轮将其减一,然后可以在当前选择的齿轮的右边选择0个、1个或者两个的其他齿轮将其变为任何数字
2.如果这个人无法选择齿轮时,他将输掉,另一个人会获胜
题解:博弈论
简单介绍一下:
Impartial Game 简单来说,就是一个游戏,双方可以进行同样的操作,也就是说局面的移动权利是对等的(Nim 是 Impartial Game,但像国际象棋之类的就不是,因为只能动自己的棋子),唯一不同的只有移动的先后。于是,如果用一个图来表示这个游戏,那么图的顶点就对应于一个游戏状态,图的边就对应于一个合法的移动。
假如在一个 Impartial Game 当中,终结状态只有一个,并且局面是不可重现的,那么整个游戏图就是一个 DAG(Directed Acyclic Graph, 有向无环图),这种情况下,可以将其等效成一个 Nim 游戏。
首先再回顾一下 Nim,有若干堆石子,A 和 B 交替移动,每次只能从某一堆中取出若干个石子,最后无法移动者必输。Nim 的结论是,将所有堆的石子数全部取异或,如果结果是 0,那么这个状态是先行者负,否则先行者胜。
然后,每堆石子其实是一个独立的 Nim,我们对于一些满足以上条件的 Impartial Game,就可以将其归约,等效于一个 Nim 游戏,他的胜负状态等效为一个 Nimber 数。至于怎么归约,就用到下面的 Sprague-Grundy 定理了,那么,下面直接上结论,要搞清楚原理,请读者自己看 Wikipedia。
Sprague-Grundy定理:对一个 Impartial Game 的状态,其等效游戏的 Nimber 数,就等于所有其后继状态 Nimber 数的 Mex 函数值。
Mex 函数:这个函数的接受一个自然数集 A,输出自然数集中减去 A 之后最小的那个整数。例如 Mex({0,1,3,4}) = 2, Mex({1,2,3}) = 0, Mex({}) = 0。
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 7777777; const int maxn = 2e2 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; char s[maxn]; int vis[maxn]; int mex[maxn]; int main() { #ifndef ONLINE_JUDGE FIN #endif for(int i = 0; i <= maxn; i++) { memset(vis, 0, sizeof(vis)); for(int j = 0; j < i; j++) { for(int k = 0; k < i; k++) { vis[mex[j]^mex[k]] = true; } } mex[i] = 0; while(vis[mex[i]]) mex[i]++; } int n; while(scanf("%d %s", &n, s) != EOF) { int ans = 0; for(int i = 0; i < n; i++) { if ((s[i] - '0') % 2 != 0) { ans ^= mex[n - i]; } } if (ans) printf("TATA "); else printf("TYNATI "); } }
I:
题意:有一个游戏,现在一共有n个人,给出n个关系,如果第i个人去的话,第a[i]个人也去
题解:一开始觉得无从下手,后来听了zgq大佬的讲解后恍然大悟,第i个人去第a[i]个人也去的话,这就形成了一组关系, 我们将这组关系作为一条边记录下来,那么这n组关系就会形成一个森林,将这个森林的边反向,将每一个被连了的点打上标记,那么没有边连的点就可以作为森林中每颗树的根节点,以根节点跑一遍dfs序,那么这个点能否到达就可以直接O(1)判断这个点的dfs序是否在另一个点内即可
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; struct EDGE { int v, nxt; } edge[maxn << 2]; int head[maxn], tot; void addd_edge(int u, int v) { edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++; } int cur; int l[maxn]; int r[maxn]; void dfs(int u) { l[u] = ++cur; for(int i = head[u]; i != -1; i = edge[i].nxt) { dfs(edge[i].v); } r[u] = ++cur; } int vis[maxn]; int main() { #ifndef ONLINE_JUDGE FIN #endif memset(head, -1, sizeof(head)); int n, m; scanf("%d%d", &n, &m); for(int i = 0, v; i < n; i++) { scanf("%d", &v); if(v != -1) { addd_edge(v, i); vis[i] = 1; } } for(int i = 0; i < n; i++) { if(!vis[i]) dfs(i); } while(m--) { int u, v; scanf("%d%d", &v, &u); if(l[u] <= l[v] && r[u] >= r[v]) { cout << "Yes" << endl; } else { cout << "No " << endl; } } return 0; }
L:
题意:有一个n个点的树,小明从起点出发,问他最多可以经过多少点,每个点不能经过两次
题解:从起点bfs一遍即可
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; struct EDGE { int v, nxt; } edge[maxn]; int head[maxn]; int tot; void add_edge(int u, int v) { edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++; } struct node { int u, cnt; node() {}; node(int a, int b) { u = a, cnt = b; } }; bool vis[maxn]; int n, a; int bfs() { memset(vis, 0, sizeof(vis)); queue<node> q; q.push(node(a, 1)); int ans = 0; vis[a] = 1; while(!q.empty()) { node tmp = q.front(); int u = tmp.u; q.pop(); ans = tmp.cnt; for(int i = head[u]; i != -1; i = edge[i].nxt) { if(!vis[edge[i].v]) { q.push(node(edge[i].v, ans + 1)); vis[edge[i].v] = 1; } } } return ans; } int main() { #ifndef ONLINE_JUDGE FIN #endif memset(head, -1, sizeof(head)); tot = 0; scanf("%d%d", &n, &a); for(int i = 1, u, v; i < n; i++) { scanf("%d%d", &u, &v); add_edge(u, v); add_edge(v, u); } printf("%d ", bfs()); return 0; }