• Codeforces Round #232 (Div. 1)


    这次运气比较好,做出两题。本来是冲着第3题可以cdq分治做的,却没想出来,明天再想好了。

    A. On Number of Decompositions into Multipliers

    题意:n个数a1,a2, a3...an求n个数相乘与a1*a2*a3*a4...an相等的排列个数。

    分析:首先应该对ai分解质因数,求出所有ai中质因数及个数,枚举排列中每个数包含的质因数个数,例如质因数qi,有ni个,相应的排列中数包含质因数qi个数设为x1,x2,....xn, x1+x2+x3..+xn = ni , 那么对于qi共有C(ni+n-1, n-1)种情况。简单来说就是将ni分成n部分,这样想:有ni个球,需要分成n部分,也就是在n个球中插入n-1根木棍,这样分成n部分就相当于ni+n-1中选n-1个位置。最后把所有质因子可能的划分情况相乘起来就行了。

    注意:分解质因数最后一个质因数可能很大!

    代码:

     1 #include <bits/stdc++.h>
     2 #define in freopen("solve_in.txt", "r", stdin);
     3 #define bug(x) printf("Line %d : >>>>>>>
    ", (x));
     4 #define pb push_back
     5 
     6 using namespace std;
     7 typedef long long LL;
     8 typedef map<int, int> Mps;
     9 const int M = (int)1e9+7;
    10 const int maxn = 555;
    11 const int maxm = (int)1e5 + 100;
    12 LL inv[maxn];
    13 int a[maxn];
    14 Mps Div;
    15 vector<int> dv;
    16 
    17 LL powmod(LL a, LL b) {
    18     LL res = 1;
    19     while(b) {
    20         if(b&1)
    21             res = (res*a)%M;
    22         b >>= 1;
    23         a = (a*a)%M;
    24     }
    25     return res;
    26 }
    27 void getInv(int n) {
    28     for(int i = 1; i < n; i++) {
    29         inv[i] = powmod(i, M-2);
    30     }
    31 }
    32 void getDiv(int x) {
    33     int m = (int)sqrt(x+.5);
    34     for(int i = 2; i <= m; i++) {
    35         if(x%i == 0) {
    36             if(Div[i] == 0)
    37                 dv.pb(i);
    38             while(x%i == 0) {
    39                 Div[i]++;
    40                 x/=i;
    41             }
    42         }
    43     }
    44     if(x > 1) {
    45         if(Div[x] == 0)
    46             dv.pb(x);
    47         Div[x]++;
    48     }
    49 }
    50 LL nCr(LL n, LL m) {
    51     LL res = 1;
    52     for(int i = 0; i < m; i++) {
    53         res = res*(n-i)%M*inv[i+1]%M;
    54         if(res < 0)
    55             res += M;
    56     }
    57     return (res + M)%M;
    58 }
    59 int main() {
    60 
    61     getInv(maxn);
    62     int n;
    63     scanf("%d", &n);
    64     for(int i = 1; i <= n; i++) {
    65         scanf("%d", a+i);
    66         getDiv(a[i]);
    67     }
    68     LL ans = 1;
    69     for(int i = 0; i < (int)dv.size(); i++) {
    70         int x = dv[i];
    71         ans = ans*nCr(Div[x]+n-1, n-1)%M;
    72     }
    73     cout<<ans<<endl;
    74     return 0;
    75 }
    View Code

    B. On Sum of Fractions

    题意:给定n, u(i)表示不超过i的最大质数, v(i)表示大于i的最小质数。求对于所有的2<= i <= n , sum{1/(u(i)*v(i)}, 最简分式结果。

    分析:

    列出n的前几个数的1/u(i)*v(i),发现对于两个相邻素数pi, pi+1间的数i, 1/u(i)*v(i)结果是一样的。也就是说 对于  pi <= x   < pi+1, sum{1/u(x)v(x)},化简后就是, 1/u(x)-1/v(x), 得到这个结论后,每次找到大于n的一个素数pi+1,结果就变成两部分, x < pi, 和 pi <= x < n, 第一部分化简就是1/2-1/pi ,第二部分:n-pi+1/(pi*pi+1), 两者之和合并一下就会得到一个表达式:2*(n+1)-2*(pi+pi+1)-pi*pi+1/(2*pi*pi+1)。求质数,用Miller-Rabin法判断前后两个质数就可以了。

    代码:

     1 #include <bits/stdc++.h>
     2 #define in freopen("solve_in.txt", "r", stdin);
     3 #define bug(x) printf("Line %d : >>>>>>>
    ", (x));
     4 #define pb push_back
     5 
     6 using namespace std;
     7 typedef pair<int, int> PII;
     8 typedef long long LL;
     9 typedef map<int, int> Mps;
    10 
    11 LL powmod(LL a, LL b, LL c) {
    12     LL res = 1;
    13     while(b) {
    14         if(b&1) res = res*a%c;
    15         b >>= 1;
    16         a = (a*a)%c;
    17     }
    18     return res;
    19 }
    20 bool test(int n, int a, int d) {
    21     if(n == 2)return true;
    22     if(n == a) return true;
    23     if((n&1) == 0) return false;
    24     while(!(d&1)) d >>= 1;
    25     int t = powmod(a, d, n);
    26     while((d != n-1) && (t != 1) && (t != n-1)) {
    27         t = (LL)t*t%n;
    28         d <<= 1;
    29     }
    30     return (t == n-1) || (d&1) == 1;
    31 
    32 }
    33 bool isPrime(int n) {
    34     if(n < 2) return false;
    35     int a[] = {2, 3, 61};
    36     for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false;
    37     return true;
    38 }
    39 pair<LL, LL> getPrime(LL n) {
    40     LL x = n;
    41     x++;
    42     PII ans;
    43     while(1) {
    44         if(isPrime(x)) {
    45             ans.first = x;
    46             break;
    47         }
    48         x++;
    49     }
    50     x = n;
    51     while(1) {
    52         if(isPrime(x)) {
    53             ans.second = x;
    54             break;
    55         }
    56         x--;
    57     }
    58     return ans;
    59 }
    60 LL getGcd(LL a, LL b) {
    61     return !b ? a : getGcd(b, a%b);
    62 }
    63 int main() {
    64 
    65     int T;
    66     int n;
    67     for(int t = scanf("%d", &T); t <= T; t++) {
    68         scanf("%d", &n);
    69         if(n == 2) {
    70             puts("1/6");
    71         } else {
    72             PII u = getPrime(n);
    73             LL x = u.first, y = u.second;
    74             LL a = 2*(n+1)-2*(x+y)+x*y;
    75             LL b = 2*x*y;
    76             LL c = getGcd(a, b);
    77             printf("%I64d/%I64d
    ", a/c, b/c);
    78         }
    79     }
    80     return 0;
    81 }
    View Code

    C. On Changing Tree

    题意:一棵n个结点的树,n <= 3*10^5, 给定q个操作。两种类型:

    1 v x k ,给v及v子树上结点增加x-i*k,i表示子树上离v的距离

    2 v,询问v结点上的值。

    分析:

    经过一上午的使劲YY,终于想到了CDQ分治的做法,其实比普通树状数组做法要慢,而且难写(也可能是我写得太挫了),复杂度最坏可能达到O(n*log^2n).1200ms能过也算是走运。

    简要思路:首先将所有操作按照v结点的深度由大到小拍个序,具体分治的时候,对于原始编号在[l,r]的操作,要将它分成两部分,<= m 和>m 部分,然后考虑编号<=m,的修改操作(操作1) 对编号>m的询问操作(操作2)影响,其实也就是用操作1对所有影响的的要询问的结点的值更新。但是又不能针对每一<=m的操作1,去更新可能影响到的>m操作2, 这样复杂度会很高,那么问题关键就在于怎么按照深度的顺序将操作1作用累积起来,每次更新对结点v影响时,只需要考虑v到根节点的路径上最靠近v的一个操作1。

    合并两个同一棵子树但是不同深度的操作1的影响时,例如1 v1 x1 k1, 1 v2 x2 k2, dep[v1] <= dep[v2],将v1合并到v2时,新的x =  x1 - (dep[v2]-dep[v1])*k1 + x2, 新的k = k1+k2。同时在询问和更新某个结点v的上方且最靠近的v的操作1对应的结点时是利用线段树维护的,具体是将子树对应的叶节点一一编号,然后看做区间,将对应结点更新时,只需要将该节点的子树包含的叶子节点的区间进行更新,例如v对应叶子节点编号[L,R]只需要将一个标记cover设置为v,表示该段叶子结点对应的子树的根为最新的。这样做的依据是树中每棵子树包含的叶子结点都不同,但是可以连续编号的。

    说的有点复杂,还是普通方法简单,这个也只是为了练习CDQ分治。||--

    代码:

      1 /*Time 2014 09 01 , 10:22
      2 
      3 */
      4 #include <bits/stdc++.h>
      5 #define in freopen("solve_in.txt", "r", stdin);
      6 #define bug(x) printf("Line %d : >>>>>>>
    ", (x));
      7 #define lson rt<<1, l, m
      8 #define rson rt<<1|1, m+1, r
      9 #define inf 0x0f0f0f0f
     10 #define pb push_back
     11 
     12 using namespace std;
     13 typedef long long LL;
     14 const int maxn = 3*(int)1e5 + 100;
     15 const int M = (int)1e9 + 7;
     16 vector<int> g[maxn];
     17 int ll[maxn], rr[maxn], dep[maxn], rk[maxn], t1[maxn], t2[maxn];
     18 int cover[maxn<<2];
     19 int ans[maxn], x[maxn], k[maxn];
     20 int qN;
     21 int cnt, ct, vis[maxn];
     22 
     23 struct Query
     24 {
     25     int type;
     26     int v, x, k;
     27 
     28 } qu[maxn];
     29 bool cmp(const int &a, const int &b)
     30 {
     31     return dep[qu[a].v] < dep[qu[b].v];
     32 }
     33 void dfs(int u)
     34 {
     35     if(g[u].size() == 0)
     36     {
     37         ll[u] = rr[u] = ++cnt;
     38         return;
     39     }
     40     else ll[u] = inf, rr[u] = 0;
     41     for(int i = 0; i < g[u].size(); i++)
     42     {
     43         int v = g[u][i];
     44         dep[v] = dep[u]+1;
     45         dfs(v);
     46         ll[u] = min(ll[u], ll[v]);
     47         rr[u] = max(rr[u], rr[v]);
     48     }
     49 }
     50 void pushDown(int rt)
     51 {
     52     if(cover[rt] != -1)
     53     {
     54         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
     55         cover[rt] = -1;
     56     }
     57 }
     58 void update(int rt, int l, int r, int L, int R, int u)
     59 {
     60     if(L <= l && R >= r)
     61     {
     62         cover[rt] = u;
     63         return;
     64     }
     65     pushDown(rt);
     66     int m = (l+r)>>1;
     67     if(L <= m)
     68     update(lson, L, R, u);
     69     if(R > m)
     70     update(rson, L, R, u);
     71 }
     72 void query(int rt, int l, int r, int L, int R)
     73 {
     74     if(cover[rt] != -1)
     75     {
     76         qN = cover[rt];
     77         return;
     78     }
     79     pushDown(rt);
     80     int m = (l+r)>>1;
     81     if(L <= m)
     82         query(lson, L, R);
     83     if(qN == -1 && R > m)
     84         query(rson, L, R);
     85     return;
     86 }
     87 void solve(int l, int r)
     88 {
     89     if(l >= r)
     90     {
     91         return;
     92     }
     93     int m = (l+r)>>1;
     94     t1[0] = t2[0] = 0;
     95     for(int i = l; i <= r; i++)
     96     {
     97         if(rk[i] <= m)
     98         {
     99             t1[++t1[0]] = rk[i];
    100         }
    101         else
    102         {
    103             t2[++t2[0]] = rk[i];
    104         }
    105     }
    106     queue<int> q1, q2;
    107     for(int i = l; i <= r; i++)
    108     {
    109         if(i <= m)
    110         {
    111             rk[i] = t1[i-l+1];
    112             if(qu[rk[i]].type == 1)
    113             {
    114                 q1.push(rk[i]);
    115             }
    116         }
    117         else
    118         {
    119             rk[i] = t2[i-m];
    120             if(qu[rk[i]].type == 2)
    121                 q2.push(rk[i]);
    122         }
    123     }
    124     cover[1] = 0;
    125     ct++;
    126     while(!q2.empty())
    127     {
    128         int xx = q2.front();
    129         q2.pop();
    130         int v1 = qu[xx].v;
    131         while(!q1.empty() && dep[qu[q1.front()].v] <= dep[v1])
    132         {
    133             int  yy = q1.front();
    134             q1.pop();
    135             int v2 = qu[yy].v;
    136             int x2 = qu[yy].x;
    137             int k2 = qu[yy].k;
    138             qN = -1;
    139             query(1, 1, cnt, ll[v2], rr[v2]);
    140             x[v2] = (x2+x[qN])%M-(LL)(dep[v2]-dep[qN])%M*(LL)k[qN]%M;
    141             if(x[v2] < 0) x[v2] += M;
    142             k[v2] = (k2+k[qN])%M;
    143             update(1, 1, cnt, ll[v2], rr[v2], v2);
    144         }
    145         qN = -1;
    146         query(1, 1, cnt, ll[v1], rr[v1]);
    147         ans[xx] = ((ans[xx]+x[qN])%M-(LL)(dep[v1]-dep[qN])%M*(LL)k[qN]%M+M)%M;
    148     }
    149     solve(l, m);
    150     solve(m+1, r);
    151 }
    152 int main()
    153 {
    154 
    155     int n, q;
    156     scanf("%d", &n);
    157     for(int i = 1; i <= n-1; i++)
    158     {
    159         int u = i+1, v;
    160         scanf("%d", &v);
    161         g[v].pb(u);
    162     }
    163     dep[1] = 1;
    164     dfs(1);
    165     scanf("%d", &q);
    166     for(int i = 1; i <= q; i++)
    167     {
    168         rk[i] = i;
    169         scanf("%d", &qu[i].type);
    170         if(qu[i].type == 1)
    171         {
    172             scanf("%d%d%d", &qu[i].v, &qu[i].x, &qu[i].k);
    173         }
    174         else scanf("%d", &qu[i].v);
    175     }
    176     sort(rk+1, rk+q+1, cmp);
    177 //    for(int i = 1; i <= q; i++)
    178 //        cout<<qu[rk[i]].v<<endl;
    179     solve(1, q);
    180     for(int i = 1; i <= q; i++)
    181     {
    182         if(qu[i].type == 2)
    183         {
    184             printf("%d
    ", ans[i]);
    185         }
    186     }
    187     return 0;
    188 }
    View Code
  • 相关阅读:
    Java 重写(Override)与重载(Overload)
    Java 继承
    Java 异常处理
    Java Scanner 类
    Java 流(Stream)、文件(File)和IO
    Java 方法
    Java 正则表达式
    Beta冲刺——代码规范、冲刺任务与计划
    Beta冲刺——凡事预则立
    Beta冲刺——问题总结博客(事后诸葛亮和组员交换事宜)
  • 原文地址:https://www.cnblogs.com/rootial/p/3948478.html
Copyright © 2020-2023  润新知