zoukankan      html  css  js  c++  java
  • 第四周 3.20-3.26

    3.20

    HDU 5647 DZY Loves Connecting

    不能直接逆元搞,因为可能会变成0。(据说可以特判一下。

    然而直接dp[0]子树方案数,dp[1]子树贡献一次dp就可以了。

    考虑当前节点新加一个孩子树,增加的贡献分两部分,

    一部分是原来树节点的贡献,增加原来的答案×新增孩子树方案数,

    另一部分是新增孩子树的贡献,增加原来方案数×新增孩子树答案。

     1 #pragma comment(linker, "/STACK:102400000,102400000")
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 typedef long long LL;
     8 const LL mod = 1e9 + 7;
     9 const int maxn = 2e5 + 10;
    10 
    11 // tree
    12 int cnt, h[maxn];
    13 struct edge
    14 {
    15     int to, pre;
    16 } e[maxn<<1];
    17 
    18 void add(int from, int to)
    19 {
    20     cnt++;
    21     e[cnt].pre = h[from];
    22     e[cnt].to = to;
    23     h[from] = cnt;
    24 }
    25 
    26 void init()
    27 {
    28     cnt = 0;
    29     memset(h, 0, sizeof(h));
    30 }
    31 
    32 // dp
    33 LL dp[maxn][2];
    34 void dfs(int x, int f)
    35 {
    36     dp[x][0] = dp[x][1] = 1;
    37     for(int i = h[x]; i; i = e[i].pre)
    38     {
    39         int to = e[i].to;
    40         if(to == f) continue;
    41         dfs(to, x);
    42         dp[x][1] = (dp[x][1] * (dp[to][0] + 1) + dp[x][0] * dp[to][1]) % mod;
    43         dp[x][0] = dp[x][0] * (dp[to][0] + 1) % mod;
    44     }
    45 }
    46 
    47 int main(void)
    48 {
    49     int T;
    50     scanf("%d", &T);
    51     while(T--)
    52     {
    53         init();
    54         int n;
    55         scanf("%d", &n);
    56         for(int i = 2; i <= n; i++)
    57         {
    58             int p;
    59             scanf("%d", &p);
    60             add(i, p), add(p, i);
    61         }
    62         dfs(1, 0);
    63         LL ans = 0;
    64         for(int i = 1; i <= n; i++) ans = (ans + dp[i][1]) % mod;
    65         printf("%I64d
    ", ans);
    66     }
    67     return 0;
    68 }
    Aguin

    HDU 5648 DZY Loves Math

    预处理每个数的子集( 关于j = (j - 1) & i 这个飘逸写法我果然不是最后一个知道的- -。

    枚举每对a = i & j, b = i | j,那么a就是i和j公用的bit,接下来任务就是把剩下的bit(即b - a)分配给i和j。

    考虑把bit分给i,下界是b - m,小于这个值j就会大于m炸掉,上界是n - a,否则i爆掉。

    然后在b - a的子集里面二分找上下界之间的个数就好了。

    具体过程就是这样,但是要注意如果公共部分是0,两边至少都分配一个bit,因为i,j要正数。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <vector>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long LL;
     7 const int maxn = 1 << 16;
     8 vector<int> A[maxn];
     9 int n, m, len;
    10 LL ans;
    11 
    12 int gcd(int a, int b)
    13 {
    14     if(!b) return a;
    15     return a % b ? gcd(b, a % b) : b;
    16 }
    17 
    18 int get(int left, int x)
    19 {
    20     if(x < 0) return 0;
    21     int l = 0, r = A[left].size() - 1, mid;
    22     while(l < r)
    23     {
    24         mid = r - (r - l) / 2;
    25         if(A[left][mid] <= x) l = mid;
    26         else r = mid - 1;
    27     }
    28     return l + 1;
    29 }
    30 
    31 void dfs(int a, int b, int d)
    32 {
    33     if(d == len)
    34     {
    35         int left = b - a, l = left + a - m, r = n - a;
    36         if(!a) r = min(r, left - 1), l = max(l, 1);
    37         if(l > r) return;
    38 //        printf("a = %d , b = %d, gcd = %d, cnt = %d
    ", a, b, gcd(a,b), get(left, r) - get(left, l - 1));
    39         ans += (LL) gcd(a, b) * (get(left, r) - get(left, l - 1));
    40         return;
    41     }
    42     dfs(a + (1 << d), b + (1 << d), d + 1);
    43     dfs(a, b + (1 << d), d + 1);
    44     dfs(a, b, d + 1);
    45 }
    46 
    47 int main(void)
    48 {
    49     for(int i = 0; i < maxn; i++)
    50     {
    51         for(int j = i; ; j = (j - 1) & i)
    52         {
    53             A[i].push_back(j);
    54             if(!j) break;
    55         }
    56         reverse(A[i].begin(), A[i].end());
    57     }
    58     int T;
    59     scanf("%d", &T);
    60     while(T--)
    61     {
    62         scanf("%d %d", &n, &m);
    63         if(n < m) swap(n, m);
    64         len = 0;
    65         while((1 << len) <= n) len++;
    66         ans = 0;
    67         dfs(0, 0, 0);
    68         printf("%I64d
    ", ans);
    69     }
    70     return 0;
    71 }
    Aguin

    3.21

    HDU 5649 DZY Loves Sorting

    标算巧妙。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 const int maxn = 1e5 + 10;
     6 int a[maxn], sum[maxn<<2], tag[maxn<<2];
     7 int M, op[maxn], L[maxn], R[maxn];
     8 
     9 void gather(int p)
    10 {
    11     sum[p] = sum[p<<1] + sum[p<<1|1];
    12 }
    13 
    14 void push(int p, int m)
    15 {
    16     if(tag[p])
    17     {
    18         tag[p<<1] = tag[p];
    19         tag[p<<1|1] = tag[p];
    20         sum[p<<1] = tag[p] == -1 ? 0 : (m - (m >> 1));
    21         sum[p<<1|1] = tag[p] == -1 ? 0 : (m >> 1);
    22         tag[p] = 0;
    23     }
    24 }
    25 
    26 void build(int p, int l, int r)
    27 {
    28     tag[p] = 0;
    29     if(l < r)
    30     {
    31         int mid = (l + r) >> 1;
    32         build(p<<1, l, mid);
    33         build(p<<1|1, mid + 1, r);
    34         gather(p);
    35     }
    36     else sum[p] = a[l] > M ? 1 : 0;
    37 }
    38 
    39 void modify(int p, int tl, int tr, int l, int r, int v)
    40 {
    41     if(tr < l || r < tl) return;
    42     if(l <= tl && tr <= r)
    43     {
    44         tag[p] = v;
    45         sum[p] = tag[p] == -1 ? 0 : (tr - tl + 1);
    46         return;
    47     }
    48     push(p, tr - tl + 1);
    49     int mid = (tl + tr) >> 1;
    50     modify(p<<1, tl, mid, l, r, v);
    51     modify(p<<1|1, mid+1, tr, l, r, v);
    52     gather(p);
    53 }
    54 
    55 int query(int p, int tl, int tr, int l, int r)
    56 {
    57     if(tr < l || r < tl) return 0;
    58     if(l <= tl && tr <= r) return sum[p];
    59     push(p, tr - tl + 1);
    60     int mid = (tl + tr) >> 1;
    61     int ret = query(p<<1, tl, mid, l, r);
    62     ret += query(p<<1|1, mid+1, tr, l, r);
    63     return ret;
    64 }
    65 
    66 int main(void)
    67 {
    68     int T;
    69     scanf("%d", &T);
    70     while(T--)
    71     {
    72         int n, m, k;
    73         scanf("%d %d", &n, &m);
    74         for(int i = 1; i <= n; i++) scanf("%d", a + i);
    75         for(int i = 1; i <= m; i++) scanf("%d %d %d", op + i, L + i, R + i);
    76         scanf("%d", &k);
    77         int l = 1, r = n;
    78         while(l < r)
    79         {
    80             M = l + (r - l) / 2;
    81             build(1, 1, n);
    82             for(int i = 1; i <= m; i++)
    83             {
    84                 int tmp = query(1, 1, n, L[i], R[i]);
    85                 if(op[i]) modify(1, 1, n, L[i], L[i] + tmp - 1, 1),
    86                           modify(1, 1, n, L[i] + tmp, R[i], -1);
    87                 else modify(1, 1, n, L[i], R[i] - tmp, -1),
    88                      modify(1, 1, n, R[i] - tmp + 1, R[i], 1);
    89             }
    90             if(query(1, 1, n, k, k)) l = M + 1;
    91             else r = M;
    92         }
    93         printf("%d
    ", r);
    94     }
    95     return 0;
    96 }
    Aguin

    3.22

    CF 653 D Delivery Bears

    精度死QAQ

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <queue>
      5 #include <algorithm>
      6 using namespace std;
      7 const int INF = 1e7;
      8 const int maxn = 555;
      9 const double eps = 1e-6;
     10 int f[maxn], t[maxn], c[maxn];
     11 int lv[maxn], it[maxn];
     12 int cnt, h[maxn];
     13 
     14 struct edge
     15 {
     16     int to, pre, cap;
     17 } e[maxn<<1];
     18 
     19 void init()
     20 {
     21     memset(h, -1, sizeof(h));
     22     cnt = 0;
     23 }
     24 
     25 void add(int from, int to, int cap)
     26 {
     27     e[cnt].pre = h[from];
     28     e[cnt].to = to;
     29     e[cnt].cap = cap;
     30     h[from] = cnt;
     31     cnt++;
     32 }
     33 
     34 void ad(int from, int to, int cap)
     35 {
     36     add(from, to, cap);
     37     add(to, from, 0);
     38 }
     39 
     40 void bfs(int s)
     41 {
     42     memset(lv, -1, sizeof(lv));
     43     queue<int> q;
     44     lv[s] = 0;
     45     q.push(s);
     46     while(!q.empty())
     47     {
     48         int v = q.front(); q.pop();
     49         for(int i = h[v]; i >= 0; i = e[i].pre)
     50         {
     51             int cap = e[i].cap, to = e[i].to;
     52             if(cap > 0 && lv[to] < 0)
     53             {
     54                 lv[to] = lv[v] + 1;
     55                 q.push(to);
     56             }
     57         }
     58     }
     59 }
     60 
     61 int dfs(int v, int t, int f)
     62 {
     63     if(v == t) return f;
     64     for(int &i = it[v]; i >= 0; i = e[i].pre)
     65     {
     66         int &cap = e[i].cap, to = e[i].to;
     67         if(cap > 0 && lv[v] < lv[to])
     68         {
     69             int d = dfs(to, t, min(f, cap));
     70             if(d > 0)
     71             {
     72                 cap -= d;
     73                 e[i^1].cap += d;
     74                 return d;
     75             }
     76         }
     77     }
     78     return 0;
     79 }
     80 
     81 int Dinic(int s, int t)
     82 {
     83     int flow = 0;
     84     while(1)
     85     {
     86         bfs(s);
     87         if(lv[t] < 0) return flow;
     88         memcpy(it, h, sizeof(it));
     89         int f;
     90         while((f = dfs(s, t, INF)) > 0) flow += f;
     91     }
     92 }
     93 
     94 int main(void)
     95 {
     96     int n, m, x;
     97     scanf("%d %d %d", &n, &m, &x);
     98     for(int i = 1; i <= m; i++) scanf("%d %d %d", f + i, t + i, c + i);
     99     double l = 0, r = 1e6, mid;
    100     while((r - l) * x > eps)
    101     {
    102         init();
    103         mid = (l + r) / 2;
    104         for(int i = 1; i <= m; i++) ad(f[i], t[i], min(1.0 * x, c[i] / mid));
    105         if(Dinic(1, n) >= x) l = mid;
    106         else r = mid;
    107     }
    108     printf("%.9f
    ", l * x);
    109     return 0;
    110 }
    Aguin

    3.23

    什么都没干。

    3.24

    CF 653 G Move by Prime

    由于对于每个质因子而言,它们对答案的贡献是独立的,所以分开考虑。

    对于质因子p,n个数p的指数递增排序后为e1、e2……en。

    考虑整个序列,怎么操作能使得move最少呢。

    如果n为奇数,mid = e(n+1)/2,那么把所有的数都变为mid是最优的。

    因为mid前面后面各有(n-1)/2个数,如果要把所有数转变为mid+1,

    那么它前面的(n-1)/2个数都要多move一次,它后面的(n-1)/2数可以少move一次,

    但是它自己也要多move一次,所以不如mid优,同理取mid-1也不如mid优。

    类似的考虑n为偶数的情况,取mid为介于e(n/2)与e(n+2)/2之间的任意数均可。

    那么把整个序列全部变为mid需要几步呢。

    可以一对一对的考虑。

    把en与e1都变成mid需要en - e1步,

    把e(n-1)与e2都变成mid需要e(n-1) - e2步,

    ………………………………………………………………

    所以总的move就是sigma(大于mid的数) - sigma(小于mid的数)

    所以对于1~n的任意一个数,包含它的子序列一共有2^(n-1)个。

    假设在a个序列中这个数处于序列的前半段,b个序列中这个数处于序列的后半段,c个序列中这个数处于序列的中间。

    那么这个数仅考虑因子p对答案的贡献就是(b - a) * ek。

    我们把(b - a)称为ek这个项的系数,仅考虑p的总答案就是sigma(系数k * ek)。

    如何计算a和b呢。

    可以考虑多项式(1 + x)^(k - 1) * (1 + x ^ (-1) )^(n - k)。

    b就是正指数项的系数和,a就是负指数项系数和,c就是常数。

    预处理组合数,然后就能计算每个数ek的系数。

    由于ek的取值很有限(小于20),所以我们可以把系数求和,然后把e值相同的项一起求和。

    总的复杂度就是把每个数分解的复杂度。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 typedef long long LL;
     6 const LL mod = 1e9 + 7;
     7 const int maxn = 3e5 + 1;
     8 LL C[maxn], e[maxn], s[maxn];
     9 int t[maxn], cnt[maxn][20];
    10 
    11 // inv
    12 LL qpow(LL a, int b)
    13 {
    14     LL ret = 1LL;
    15     while(b)
    16     {
    17         if(b & 1) ret = ret * a % mod;
    18         a = a * a % mod;
    19         b >>= 1;
    20     }
    21     return ret;
    22 }
    23 
    24 LL inv(LL x)
    25 {
    26     return qpow(x, mod - 2);
    27 }
    28 
    29 int main(void)
    30 {
    31     int n;
    32     scanf("%d", &n);
    33     for(int i = 1; i <= n; i++) scanf("%d", t + i);
    34     C[0] = 1LL;
    35     for(int i = 1; i < n; i++) C[i] = C[i-1] * (n - i) % mod * inv(i) % mod;
    36     for(int i = 0; i < n - 1; i++) e[1] = (e[1] - C[i] + mod) % mod;
    37     for(int i = 2; i <= n; i++) e[i] = (e[i-1] + C[n-i] + C[n-i+1]) % mod;
    38     for(int i = 1; i <= n; i++) s[i] = (s[i-1] + e[i]) % mod;
    39     for(int i = 1; i <= n; i++)
    40     {
    41         for(int j = 2; j * j <= t[i]; j++)
    42         {
    43             int tmp = 0;
    44             while(t[i] % j == 0) t[i] /= j, tmp++;
    45             if(tmp) cnt[j][tmp]++;
    46         }
    47         if(t[i] > 1) cnt[t[i]][1]++;
    48     }
    49     LL ans = 0LL;
    50     for(int i = 1; i < maxn; i++)
    51     {
    52         cnt[i][0] = n;
    53         for(int j = 1; j < 20; j++) cnt[i][0] -= cnt[i][j];
    54         int cur = 0;
    55         for(int j = 0; j < 20; j++) ans = (ans + (s[cur+cnt[i][j]] - s[cur] + mod) * j % mod) % mod, cur += cnt[i][j];
    56     }
    57     printf("%I64d
    ", ans);
    58     return 0;
    59 }
    Aguin

    3.25

    CF 653 E Bear and Forgotten Tree 2

    先检查连通性,从2开始DFS一次,

    set维护未访问点集,然后check禁边。

    如果任一个联通块不与1相连则不可行。

    考虑1的子树数目。

    最小值为与1相连的联通块数目,最大值为n - 1 - 与1相连的禁边数。

    只要k在这个范围内都可行。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <vector>
     4 #include <set>
     5 #include <algorithm>
     6 using namespace std;
     7 const int maxn = 3e5 + 10;
     8 vector<int> G[maxn];
     9 set<int> S;
    10 
    11 bool dfs(int x)
    12 {
    13     vector<int> v;
    14     bool ret = 0;
    15     if(G[x].empty() || G[x][0] != 1) ret = 1;
    16     for(set<int> :: iterator it = S.begin(); it != S.end(); it++)
    17     {
    18         vector<int> :: iterator vit = lower_bound(G[x].begin(), G[x].end(), *it);
    19         if(vit != G[x].end() && *vit == *it) continue;
    20         v.push_back(*it);
    21     }
    22     int sz = v.size();
    23     for(int i = 0; i < sz; i++) S.erase(v[i]);
    24     for(int i = 0; i < sz; i++) ret |= dfs(v[i]);
    25     return ret;
    26 }
    27 
    28 int main(void)
    29 {
    30     int n, m, k;
    31     scanf("%d %d %d", &n, &m, &k);
    32     for(int i = 0; i < m; i++)
    33     {
    34         int u, v;
    35         scanf("%d %d", &u, &v);
    36         G[u].push_back(v);
    37         G[v].push_back(u);
    38     }
    39     for(int i = 2; i <= n; i++) S.insert(i);
    40     for(int i = 1; i <= n; i++) sort(G[i].begin(), G[i].end());
    41     int ma = n - 1 - G[1].size(), mi = 0;
    42     for(int i = 2; i <= n; i++)
    43     {
    44         if(S.find(i) == S.end()) continue;
    45         S.erase(i);
    46         if(!dfs(i)) return puts("impossible");
    47         mi++;
    48     }
    49     puts(k >= mi && k <= ma ? "possible" : "impossible");
    50     return 0;
    51 }
    Aguin

    3.26

    CF 653 F Paper task

    如果能算出每个后缀的前缀中有几个合法括号序列,

    用SA排好,每个后缀的贡献就是这个后缀的前缀中的合法括号序列数,减去相邻后缀lcp的合法括号序列数。

    于是考虑怎么搞后缀的前缀中有多少合法括号序列。

    先预处理前缀和,左括号+1右括号-1。

    把每个前缀和值对应的位置存起来,

    然后对于某个后缀,只要找到它后面第一个前缀和小于它的位置,这两个位置中前缀和与它相等的位置都是合法括号序列。

    反着用单调栈可以搞出每个后缀后面第一个前缀和小于它的位置。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <vector>
     4 #include <stack>
     5 #include <cstring>
     6 #include <algorithm>
     7 using namespace std;
     8 typedef long long LL;
     9 const int maxn = 5e5 + 10;
    10 int cnt[maxn], ed[maxn];
    11 vector<int> p[maxn<<1];
    12 vector<int> :: iterator it1, it2;
    13 stack<int> st;
    14 
    15 // SA
    16 char s[maxn];
    17 int n, k, SA[maxn], r[maxn], tmp[maxn], h[maxn];
    18 bool cmp(int i, int j)
    19 {
    20     if(r[i] != r[j]) return r[i] < r[j];
    21     return ( i + k <= n ? r[i+k] : -1 ) < ( j + k <= n ? r[j+k] : -1 );
    22 }
    23 
    24 void get_SA()
    25 {
    26     for(int i = 0; i <= n; i++)
    27     {
    28         SA[i] = i;
    29         r[i] = i < n ? s[i] : -1;
    30     }
    31     for(k = 1; k <= n; k <<= 1)
    32     {
    33         sort(SA, SA + n + 1, cmp);
    34         tmp[SA[0]] = 0;
    35         for(int i = 1; i <= n; i++) tmp[SA[i]] = tmp[SA[i-1]] + cmp(SA[i-1], SA[i]);
    36         memcpy(r, tmp, sizeof(r));
    37     }
    38     return;
    39 }
    40 
    41 void get_height()
    42 {
    43     for(int i = 0; i <= n; i++) r[SA[i]] = i;
    44     int k = 0;
    45     for(int i = 0; i < n; i++)
    46     {
    47         if(k) k--;
    48         int j = SA[r[i]-1];
    49         while(s[i+k] == s[j+k]) k++;
    50         h[r[i]] = k;
    51     }
    52     return;
    53 }
    54 
    55 int main(void)
    56 {
    57     s[0] = '~';
    58     scanf("%d %s", &n, s + 1);
    59     for(int i = 1; i <= n; i++)
    60     {
    61         cnt[i] = cnt[i-1] + (s[i] == '(' ? 1 : -1);
    62         p[cnt[i]+maxn].push_back(i);
    63     }
    64     for(int i = n; i >= 0; i--)
    65     {
    66         while(!st.empty() && cnt[st.top()] >= cnt[i]) st.pop();
    67         ed[i] = st.empty() ? n : st.top() - 1;
    68         st.push(i);
    69     }
    70     n++;
    71     get_SA();
    72     get_height();
    73     LL ans = 0LL;
    74     for(int i = 1; i < n; i++)
    75     {
    76         int q = SA[i] ? cnt[SA[i]-1] + maxn : maxn;
    77         it1 = lower_bound(p[q].begin(), p[q].end(), ed[SA[i]-1]+1);
    78         it2 = lower_bound(p[q].begin(), p[q].end(), SA[i] + h[i]);
    79         if(it2 == p[q].end() || it2 > it1) continue;
    80         ans += (LL) (it1 - it2);
    81     }
    82     printf("%I64d
    ", ans);
    83     return 0;
    84 }
    Aguin

    HDU 5653 Bomber Man wants to bomb an Array

    比较挫是没有去想这样搞的复杂度。

    区间长度n,炸弹m。

    假设均分区间,区间长n/m,所以枚举每个炸弹以及左右端点只有m×n/m×n/m=n^2/m。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 double dp[2222];
     6 int b[2222];
     7 
     8 int main(void)
     9 {
    10     int T;
    11     scanf("%d", &T);
    12     while(T--)
    13     {
    14         int n, m;
    15         scanf("%d %d", &n, &m);
    16         for(int i = 0; i <= n; i++) dp[i] = 0.0;
    17         for(int i = 1; i <= m; i++) scanf("%d", b + i), b[i]++;
    18         b[m+1] = n + 1;
    19         sort(b + 1, b + m + 1);
    20         for(int i = 1; i <= m; i++)
    21             for(int l = b[i-1] + 1; l <= b[i]; l++)
    22                 for(int r = b[i]; r < b[i+1]; r++)
    23                     dp[r] = max(dp[r], dp[l-1] + log2(r - l + 1));
    24         printf("%d
    ", (int) floor(1e6 * dp[n]));
    25     }
    26     return 0;
    27 }
    Aguin
  • 相关阅读:
    《多处理器编程的艺术》读书笔记(2) 互斥
    《多处理器编程的艺术》读书笔记(7) CLH队列锁
    rdlc 套打实现
    《多处理器编程的艺术》读书笔记(6) 队列锁
    《多处理器编程的艺术》读书笔记(3) 双线程解决方案
    《多处理器编程的艺术》读书笔记(4) 自旋锁(1)
    《多处理器编程的艺术》读书笔记(1) 并行的困境和加速比
    反色,霓虹灯,浮雕
    《多处理器编程的艺术》读书笔记(5) 自旋锁(2)
    Open ESRI shape files in Quantum GIS Anny
  • 原文地址:https://www.cnblogs.com/Aguin/p/5304188.html
Copyright © 2011-2022 走看看