CCPC-Wannafly Winter Camp Day7 (Div2, onsite)
Replay
Dup4:
- 啥都不会? 只能看着两位聚聚A题?
X:
- 模拟题不会写, 日常摔锅
- u, v分不清, 日常演员
- 又是自己没理清楚就抢键盘上机导致送了一万个罚时, 日常背锅
A:迷宫
Solved.
考虑所有人从1号点排队出发,所有人都回到自己位置的时间
让深度大的先走,这样就不会产生堵塞
那么每个人的时间就是 在1号点的等待时间+深度
取最大值即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n, a[N]; 6 vector <int> G[N]; 7 8 int deep[N], fa[N]; 9 void DFS(int u) 10 { 11 for (auto v : G[u]) if (v != fa[u]) 12 { 13 deep[v] = deep[u] + 1; 14 fa[v] = u; 15 DFS(v); 16 } 17 } 18 19 int main() 20 { 21 while (scanf("%d", &n) != EOF) 22 { 23 for (int i = 1; i <= n; ++i) G[i].clear(); 24 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 25 for (int i = 1, u, v; i < n; ++i) 26 { 27 scanf("%d%d", &u, &v); 28 G[u].push_back(v); 29 G[v].push_back(u); 30 } 31 deep[1] = 0; DFS(1); 32 vector <int> vec; 33 for (int i = 1; i <= n; ++i) if (a[i]) vec.push_back(i); 34 sort(vec.begin(), vec.end(), [](int a, int b) { return deep[a] > deep[b]; }); 35 int res = 0; 36 int cnt = 0; 37 for (auto it : vec) 38 { 39 res = max(res, cnt + deep[it]); 40 ++cnt; 41 } 42 printf("%d\n", res); 43 } 44 return 0; 45 }
C:斐波那契数列
Solved.
斐波那契数列$前n项和的通项是$
$Fib_n \& (Fib_n - 1) = Fib_n - lowbit(Fib_n)$
$S_n = 2 \cdot a_n + a_{n - 1} - 1$
打表找规律发现
后面那部分是
$1 1 2 1 1 8 1 1 2 1 1 16 1 1 2 1 1 8 1 1 2 1 1\cdots$
有对称性,可以递归求和
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 const ll MOD = (ll)998244353; 6 7 int t; ll R; 8 struct node 9 { 10 ll a[2][2]; 11 node operator * (const node &other) const 12 { 13 node res; memset(res.a, 0, sizeof res.a); 14 for (int i = 0; i < 2; ++i) 15 for (int j = 0; j < 2; ++j) 16 for (int k = 0; k < 2; ++k) 17 res.a[i][j] = (res.a[i][j] + a[i][k] * other.a[k][j] % MOD + MOD) % MOD; 18 return res; 19 } 20 }; 21 22 ll a[2][2] = 23 { 24 1, 1, 25 1, 0, 26 }; 27 28 ll b[2][2] = 29 { 30 1, 1, 31 0, 0, 32 }; 33 34 node qpow(ll n) 35 { 36 node base; 37 for (int i = 0; i < 2; ++i) 38 for (int j = 0; j < 2; ++j) 39 base.a[i][j] = a[i][j]; 40 node res; 41 for (int i = 0; i < 2; ++i) 42 for (int j = 0; j < 2; ++j) 43 res.a[i][j] = b[i][j]; 44 while (n) 45 { 46 if (n & 1) res = res * base; 47 base = base * base; 48 n >>= 1; 49 } 50 return res; 51 } 52 53 ll qpow(ll base, ll n) 54 { 55 ll res = 1; 56 while (n) 57 { 58 if (n & 1) res = (res * base) % MOD; 59 base = (base * base) % MOD; 60 n >>= 1; 61 } 62 return res; 63 } 64 65 66 ll pos[64], num[64], sum[64]; 67 ll solve(ll now) 68 { 69 if (now <= 0) return 0; 70 if (now == 1) return 1; 71 if (now == 2) return 2; 72 if (now == 3) return 4; 73 if (now == 4) return 5; 74 if (now == 5) return 6; 75 int id = upper_bound(pos + 1, pos + 62, now) - pos - 1; 76 if (pos[id] == now) return (sum[id] + num[id]) % MOD; 77 return ((solve(now - pos[id]) + solve(pos[id])) % MOD); 78 } 79 80 int main() 81 { 82 pos[1] = 6; 83 for (int i = 2; i <= 61; ++i) pos[i] = pos[i - 1] << 1; 84 num[1] = 8; 85 for (int i = 2; i <= 61; ++i) num[i] = (num[i - 1] << 1) % MOD; 86 sum[1] = 6; 87 for (int i = 2; i <= 61; ++i) sum[i] = ((sum[i - 1] << 1) % MOD + num[i - 1]) % MOD; 88 scanf("%d", &t); 89 while (t--) 90 { 91 scanf("%lld", &R); 92 ll need = 0; 93 if (R == 1) need = 1; 94 else if (R == 2) need = 2; 95 else if (R == 3) need = 4; 96 else need = (2ll * qpow(R - 2).a[0][0] % MOD + qpow(R - 3).a[0][0] % MOD - 1 + MOD) % MOD; 97 //cout << R << " " << need << " " << solve(R) << "\n"; 98 printf("%lld\n", (need - solve(R) % MOD + MOD) % MOD); 99 } 100 return 0; 101 }
D:二次函数
Solved.
枚举哪两个式子相等,做三次
考虑二元一次方程的根,令$y相同,则有$
$x_1 = -\frac{a_1 \pm \sqrt{4 \cdot y + a_1^2 - 4 \cdot b_1}}{2}$
$x_2 = -\frac{a_2 \pm \sqrt{4 \cdot y + a_2^2 - 4 \cdot b_2}}{2}$
考虑根号下一定是一个平方数
那么令$T^2 = 4 \cdot y + a_1^2 - 4 \cdot b_1$
$t^2 = 4 \cdot y + a_2^2 - 4 \cdot b_2$
$T^2 - t^2 = (T + t) \cdot (T - t) = a_1^2 - 4 \cdot b_1 - a_2^2 + 4 \cdot b_2$
$枚举差值的因数分解,得到T 和 t 再判断是否可以$
$再特判 差值为0 和 差值为1的情况$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define pll pair <ll, ll> 6 int t; 7 ll a[3], b[3]; 8 9 pll res; 10 bool solve(ll a1, ll b1, ll a2, ll b2) 11 { 12 ll t1 = (a1 * a1 - 4 * b1); 13 ll t2 = (a2 * a2 - 4 * b2); 14 ll gap = abs(t1 - t2); 15 if (gap == 0) 16 { 17 if ((t1 & 1) == (t2 & 1)) 18 { 19 res.first = 0; 20 res.second = -(a2 - a1) / 2; 21 return true; 22 } 23 else 24 return false; 25 } 26 if (gap == 1) 27 { 28 if ((t1 & 1) != (t2 & 1)) 29 { 30 if (t1 > t2 && ((a1 & 1) == 1)) 31 { 32 res.first = -(a1 + 1) / 2; 33 res.second = -a2 / 2; 34 return true; 35 } 36 else if (t1 < t2 && ((a2 & 1) == 1)) 37 { 38 res.first = -a1 / 2; 39 res.second = -(a2 + 1) / 2; 40 return true; 41 } 42 else return false; 43 } 44 } 45 for (int i = 1; i * i < gap; ++i) if (gap % i == 0 && (i + gap / i) % 2 == 0) 46 { 47 ll T = (i + gap / i) / 2; 48 ll t = (gap / i - i) / 2; 49 if (t1 < t2) swap(T, t); 50 if ((T + a1) % 2 == 0 && (t + a2) % 2 == 0) 51 { 52 res.first = -((T + a1) / 2); 53 res.second = -((t + a2) / 2); 54 return true; 55 } 56 } 57 return false; 58 } 59 60 void work() 61 { 62 for (int i = 0; i < 3; ++i) 63 for (int j = i + 1; j < 3; ++j) 64 { 65 if (solve(a[i], b[i], a[j], b[j])) 66 { 67 if (i == 0) 68 { 69 printf("%lld %lld %lld\n", res.first, j == 1 ? res.second : 0, j == 1 ? 0 : res.second); 70 } 71 else 72 printf("0 %lld %lld\n", res.first, res.second); 73 return; 74 } 75 } 76 } 77 78 int main() 79 { 80 scanf("%d", &t); 81 while (t--) 82 { 83 for (int i = 0; i < 3; ++i) scanf("%lld%lld", a + i, b + i); 84 work(); 85 } 86 return 0; 87 }
E:线性探查法
Solved.
拓扑排序?
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int MAXN = 1e6 + 10; 6 const int maxn = 1e3 + 10; 7 8 struct Edge{ 9 int to, nxt; 10 Edge(){} 11 Edge(int to, int nxt): to(to), nxt(nxt){} 12 }edge[MAXN << 1]; 13 14 struct node{ 15 int val; 16 int index; 17 node(){} 18 node(int val, int index):val(val), index(index){} 19 bool operator < (const node &other) const{ 20 return val > other.val; 21 } 22 }brr[maxn]; 23 24 int n; 25 int arr[maxn]; 26 int head[maxn], tot; 27 int du[maxn]; 28 29 void Init() 30 { 31 tot = 0; 32 memset(head, -1, sizeof head); 33 memset(du, 0, sizeof du); 34 } 35 36 void addedge(int u,int v) 37 { 38 edge[tot] = Edge(v, head[u]); head[u] = tot++; 39 } 40 41 void solve() 42 { 43 priority_queue<node>q; 44 for(int i = 0; i < n; ++i) if(du[i] == 0) 45 { 46 q.push(brr[i]); 47 } 48 int tot = 1; 49 while(!q.empty()) 50 { 51 node st = q.top(); 52 q.pop(); 53 arr[tot++] = st.val; 54 int u = st.index; 55 for(int i = head[u]; ~i; i = edge[i].nxt) 56 { 57 int v = edge[i].to; 58 --du[v]; 59 if(du[v] == 0) q.push(brr[v]); 60 } 61 } 62 } 63 64 int main() 65 { 66 while(~scanf("%d" ,&n)) 67 { 68 Init(); 69 for(int i = 0; i < n; ++i) 70 { 71 int x; 72 scanf("%d", &x); 73 int now = i; 74 int pre = x % n; 75 brr[i] = node(x, i); 76 while(now != pre) 77 { 78 now = (now - 1 + n) % n; 79 addedge(now, i); 80 du[i]++; 81 } 82 } 83 solve(); 84 for(int i = 1; i <= n; ++i) printf("%d%c", arr[i], " \n"[i == n]); 85 } 86 return 0; 87 }
F:逆序对!
Solved.
考虑两个位置的数对有多少个数异或会让他们对答案产生贡献
如果$a > b 那么从高位到地位找到第一位不同的数 这一位要放0,其他位任意的比m小的数$
$a < b 同理$
复杂度$O(n^2logn)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 1010 6 const ll MOD = (ll)998244353; 7 ll Bit[35], res; 8 int n, m, b[N]; 9 10 void solve(ll a, ll b) 11 { 12 for (int i = 31; i >= 0; --i) 13 { 14 int n1 = ((a >> i) & 1), n2 = ((b >> i) & 1); 15 if (n1 != n2) 16 { 17 ll tmp1 = m >> (i + 1); 18 ll tmp2 = m & (Bit[i] - 1); 19 ll sum = 0; 20 if((m >> i) & 1) 21 sum = (tmp1 * Bit[i] % MOD + tmp2 + 1) % MOD; 22 else 23 sum = (tmp1 * Bit[i]) % MOD; 24 if (a < b) res = (res + sum) % MOD; 25 else res = (res + m - sum + MOD) % MOD; 26 return ; 27 } 28 } 29 } 30 31 int main() 32 { 33 Bit[0] = 1; 34 for (int i = 1; i <= 32; ++i) Bit[i] = (Bit[i - 1] << 1); 35 while (scanf("%d%d", &n, &m) != EOF) 36 { 37 res = 0; 38 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 39 for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) 40 solve(b[i], b[j]); 41 printf("%lld\n", res); 42 } 43 return 0; 44 }
G:抢红包机器人
Solved.
至少存在一个机器人,枚举这一位机器人
那么它前面所有账号都是机器人,并且这种关系是传递的,DFS即可
u, v 傻傻分不清楚可还行
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int INF = 0x3f3f3f3f; 6 7 const int MAXN = 1e6 + 10; 8 const int maxn = 1e2 + 10; 9 10 struct Edge{ 11 int to, nxt; 12 Edge(){} 13 Edge(int to, int nxt):to(to), nxt(nxt){} 14 }edge[MAXN << 1]; 15 16 int n, m; 17 int head[maxn], tot; 18 int vis[maxn]; 19 int arr[maxn]; 20 21 void Init() 22 { 23 tot = 0; 24 memset(head, -1, sizeof head); 25 } 26 27 void addedge(int u,int v) 28 { 29 edge[tot] = Edge(v, head[u]); head[u] = tot++; 30 } 31 32 void DFS(int u) 33 { 34 for(int i = head[u]; ~i; i = edge[i].nxt) 35 { 36 int v = edge[i].to; 37 if(vis[v]) continue; 38 vis[v] = 1; 39 DFS(v); 40 } 41 } 42 43 int main() 44 { 45 while(~scanf("%d %d", &n, &m)) 46 { 47 Init(); 48 for(int i = 1, k; i <= m; ++i) 49 { 50 scanf("%d", &k); 51 for(int j = 1; j <= k; ++j) 52 { 53 scanf("%d", arr + j); 54 } 55 for(int u = k; u >= 1; --u) 56 { 57 for(int v = u - 1; v >= 1; --v) 58 { 59 addedge(arr[u], arr[v]); 60 } 61 } 62 } 63 int ans = INF; 64 for(int i = 1; i <= n; ++i) 65 { 66 memset(vis, 0, sizeof vis); 67 vis[i] = 1; 68 DFS(i); 69 int sum = 0; 70 for(int j = 1; j <= n; ++j) sum += vis[j]; 71 ans = min(ans, sum); 72 } 73 printf("%d\n", ans); 74 } 75 return 0; 76 }
J:强壮的排列
Solved.
打了个表? Comet OJ 支持512Kb 感人