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 }
View Code

 

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 }
View Code

 

  

 

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 }
View Code

 

 

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 }
View Code

 

 

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 }
View Code

 

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 }
View Code

 

 

J:强壮的排列

Solved.

打了个表? Comet OJ 支持512Kb  感人

posted @ 2019-01-26 19:30  Dup4  阅读(411)  评论(0编辑  收藏  举报