文章链接:http://www.cnblogs.com/Asm-Definer/p/4434601.html

题目链接:http://pan.baidu.com/s/1mgxIKli

官方数据:http://pan.baidu.com/s/1qW4wkVE

 

     看巨神们都去虐ZJOI了,蒟蒻只能默默地码着CQOI的题解……

     CQOI的难度分布也是挺神奇的,五小时五道题,三(或四)道水题一两道神题(只是对我来说比较神...),我猜让我去考我一定会写不完D题然后滚去备战高考= =

 

A.选数

 题意:

    从区间[L, H]中选出N个数(可以重复),求取出的N个数的最大公约数恰好为K的方案数。

其中$1 \leq L, H, N \leq 10^9, H - L \leq 10^5$

 分析:

    刚开始还以为这是道简单的莫比乌斯反演题,推了半天公式,发现是个依赖$\lfloor H / K \rfloor $的式子

$$\sum_{d=1}^{H/K} \mu(d) (\frac{H}{d*K} - \frac{L-1}{d*K})^N$$(由于LaTeX打取整式太不方便所以这个式子没有考虑细节)当$H/K$很大的时候mu就无法预处理了。

    后来衡中的JSX同学(http://55242.cf/)告诉我一个不错的思路:对较小的mu用线性筛预处理,对较大的mu直接暴力分解质因数。而当d比较大的时候会有很多$(\frac{H}{d*K} - \frac{L-1}{d*K})$为0的区间,遇到这些区间就跳转一下就可以了。粘一下他的核心代码:

1 for(int i = 1;i <= R;++ i) {
2     if((R/i) == (L/i)) {
3         i = min((LL)R/(R/i) ,(LL)L / i ? L/(L/i) : INF);
4         continue;
5     } else {
6         ans += (LL)quickpow((R/i)-(L/i),N) * get_mu(i);
7         ans %= mod;
8     }
9 }

    思路简单,效率也很不错。

    不过……有强迫症的同学可能会想……如果这道题表达式的后半部分不是$(\frac{H}{d*K} - \frac{L-1}{d*K})$而只有$\frac{H}{d*K}$,这个式子就不会很快变成0了。这样还是否可做呢?

    考虑到在取整后$\frac{H}{d*K}$的取值只有$\sqrt{\frac{H}{K}}$个,如果我们能快速地求出莫比乌斯的前缀和(梅腾斯函数),就可以在$O(1)$的时间内求出一段相等的区间的贡献了。

    这个$M(N) = \sum_{i=1}^N \mu(i)$看起来似乎很难的样子……其实我们可以这样转化:

$$M(N)= \sum_{i=1}^N (\sum_{d|i}\mu(d) - \sum_{d|i \land d \neq i}\mu(d) ) \\ = 1 - \sum_{i=1}^N \sum_{d|i \land d \neq i} \mu(d) \\= 1 - \sum_{i'=2}^N \sum_{d=1}^{\lfloor \frac{N}{i'} \rfloor} \mu(d) \\ = 1 - \sum_{i'=2}^N M(\lfloor \frac{N}{i'}\rfloor)$$

     这样,我们就只需在预处理出前$10^7$项梅腾斯函数后在处理较大的N时对

$\lfloor \frac{N}{i'}\rfloor$分块递归就可以快速地求出超过$10^7$的梅腾斯函数了。(这个带下取整的递推式复杂度究竟是多少呢……反正我不会分析……不过目测我们需要计算梅腾斯函数的次数非常少,所以这个复杂度已经足够了。

     然而……出题人表示我们都太Simple啦,Sometimes Naive!我们观察一下题目中的条件……“$H - L \leq 10^5$"......注意到当N个数不全相同的时候,它们的最大公约数一定不会超过其中任意两个不同数的差。于是……我们只需要将边界除以K后递推”N个数不全相同且最大公因数为i($i \leq 10^5$)"的方案数,最后特判一下N个数都相同的情况,加上递归得到的F(1)就是答案了,复杂度是优美的$(H-L) log (H-L)$。 

 代码:

 1 /***********************************************************************/
 2 /**********************By Asm.Def-Wu Jiaxin*****************************/
 3 /***********************************************************************/
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <ctime>
 8 #include <cctype>
 9 #include <algorithm>
10 #ifdef DEBUG
11 #include <sys/timeb.h>
12 #endif
13 using namespace std;
14 #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) );
15 #define getc() getchar() 
16 template<class T>inline void getd(T &x){
17     char ch = getc();bool neg = false;
18     while(!isdigit(ch) && ch != '-')ch = getc();
19     if(ch == '-')ch = getc(), neg = true;
20     x = ch - '0';
21     while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
22     if(neg)x = -x;
23 }
24 #ifdef DEBUG
25 #include <sys/timeb.h>
26 timeb Tp;
27 #endif
28 /***********************************************************************/
29 const int maxn = 100004, mod = 1000000007;
30 typedef long long LL;
31 inline int powmod(int a, int n){
32     int ans = 1;
33     while(n){if(n & 1)ans = (LL)ans * a % mod;a = (LL)a * a % mod;n >>= 1;}
34     return ans;
35 }
36 
37 inline void work(){
38     int f[maxn], N, K, L, H, i, j, t, *it;getd(N), getd(K), getd(L), getd(H);
39     L = (L - 1) / K;H /= K;
40     int len = H - L;
41     for(i = len, it = f + i;i;--i, --it){
42         t = H / i - L / i;//澶氬皯涓猧鐨勫€嶆暟
43         *it = (powmod(t, N) + mod - t) % mod;
44         for(j = i << 1;j <= len;j += i)
45             *it = (*it + mod - f[j]) % mod;
46     }
47     if(L <= 1 && H > 1)++f[1];
48     printf("%d\n", f[1]);
49 }
50 
51 int main(){
52 
53 #ifdef DEBUG
54     freopen("test.txt""r", stdin);
55     ftime(&Tp);
56     time_t Begin_sec = Tp.time, Begin_mill = Tp.millitm;
57 #elif !defined ONLINE_JUDGE
58     SetFile(cqoi15_number);
59 #endif
60     work();
61 
62 #ifdef DEBUG
63     ftime(&Tp);
64     printf("\n%.3lf sec \n", (Tp.time - Begin_sec) + (Tp.millitm - Begin_mill) / 1000.0);
65 #endif
66     return 0;
67 }
A.递推

 B.网络吞吐量

题意:

    在一个无向网络的最短路径构成的DAG上求最大流。

$|V| \leq 500, |E| \leq 100000 $ 

分析:

似乎不需要分析了,除了最短路+网络流外没有什么其他的东西……

注意到这里的原图是个稠密图,使用$O(|V|^2)$的Dijkstra 可以得到很好的运行效率。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <ctime>
  5 #include <cctype>
  6 #include <algorithm>
  7 #include <cmath>
  8 using namespace std;
  9 #define USEFREAD
 10 #ifdef USEFREAD
 11 #define InputLen 5000000
 12 char *ptr=(char *)malloc(InputLen);
 13 #define getc() (*(ptr++))
 14 #else
 15 #define getc() (getchar())
 16 #endif
 17 #define SetFile(x) (freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout))
 18 template<class T>inline void getd(T &x){
 19     char ch = getc();bool neg = false;
 20     while(!isdigit(ch) && ch != '-')ch = getc();
 21     if(ch == '-')ch = getc(), neg = true;
 22     x = ch - '0';
 23     while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
 24     if(neg)x = -x;
 25 }
 26 /***********************************************************************/
 27 const int maxn = 512, maxv = 1003;
 28 typedef long long LL;
 29 const LL INF = 0x3f3f3f3f3f3f3f3fll;
 30 int S, N, tmp[maxn][maxn], tmpcnt[maxn], val[maxn];
 31 LL dis[maxn], G[maxn][maxn];
 32 inline void init(){
 33     int M, i, u, v, d, *t = val + 1;
 34     getd(N), getd(M);S = 1 + N;
 35     while(M--){
 36         getd(u), getd(v), getd(d);LL &e = G[u][v];
 37         if(!e || e > d)e = d, G[v][u] = d;
 38     }
 39     for(i = 1;i <= N;++i, ++t)getd(*t);
 40 }
 41 
 42 struct Edge{
 43     int to, vol;Edge *op;
 44     inline void init(int t, int v, Edge *o){to = t, vol = v, op = o;}
 45 }adj[maxv][maxn];int adjcnt[maxv];
 46 
 47 inline void AddE(int u, int v, int vol){
 48     int &itu = adjcnt[u], &itv = adjcnt[v];
 49     adj[u][itu].init(v, vol, adj[v] + itv);adj[v][itv].init(u, 0, adj[u] + itu);++itu, ++itv;
 50 }
 51 
 52 inline void Dij(){
 53     memset(dis, INF, sizeof(dis));dis[1] = 0;
 54     bool tab[maxn] = {0}, inS[maxn] = {0,1};
 55     int tablist[maxn], *tabiter = tablist, i, j, v, *it, *tmpt;
 56     LL *tmpd, *e, t;
 57     for(i = 2,e = G[1]+2,tmpd = dis+2;i <= N;++i,++e,++tmpd)if(*e)
 58         *(tabiter++) = i, *tmpd = *e, tmp[i][tmpcnt[i]++] = 1;
 59     for(j = 2;j <= N;++j){
 60         if(tabiter == tablist)break;
 61         t = INF;
 62         for(it = tablist;it < tabiter;++it)if(dis[*it] < t)
 63             tmpt = it, t = dis[*it];
 64         inS[v = *(it = tmpt)] = true;
 65         e = G[v] + 2;
 66         swap(*it, *(--tabiter));
 67         for(i = 2,tmpd = dis+2;i <= N;++i,++e,++tmpd)if(*e && !inS[i]){
 68             if(*tmpd > t + *e){
 69                 *tmpd = t + *e;
 70                 *tmp[i] = v;tmpcnt[i] = 1;
 71                 if(!tab[i])*(tabiter++) = i, tab[i] = true;
 72             }
 73             else if(*tmpd == t + *e)
 74                 tmp[i][tmpcnt[i]++] = v;
 75         }
 76     }
 77     for(i = 2;i <= N;++i)for(it = tmp[i] + tmpcnt[i] - 1;it >= tmp[i];--it)
 78         AddE(*it + N, i, INF);
 79     for(i = 1;i <= N;++i)AddE(i, i + N, val[i]);
 80 }
 81 
 82 int dep[maxv], curadj[maxv];
 83 LL dfs(int cur, LL f){
 84     if(cur == N)return f;
 85     LL d = dep[cur], ans = 0, t;
 86     int &adjit = curadj[cur];
 87     Edge *it;
 88     for(;adjit < adjcnt[cur];++adjit)if((it = adj[cur]+adjit)->vol && dep[it->to] == d + 1){
 89         t = dfs(it->to, min(f, (LL)it->vol));
 90         it->vol -= t, it->op->vol += t, ans += t, f -= t;
 91         if(!f)return ans;
 92     }
 93     return ans;
 94 }
 95 #include <queue>
 96 inline bool bfs(){
 97     memset(curadj, 0sizeof(curadj));
 98     queue<int> Q;bool vis[maxv] = {0};vis[S] = true;
 99     Q.push(S);
100     int v;LL d;
101     Edge *it, *end;
102     while(!Q.empty()){
103         v = Q.front();Q.pop();d = dep[v];
104         for(it = adj[v],end = it + adjcnt[v];it < end;++it)if(it->vol && !vis[it->to])
105             dep[it->to] = d + 1, Q.push(it->to), vis[it->to] = true;
106     }
107     return vis[N];
108 }
109 
110 int main(){
111     #ifdef DEBUG
112     freopen("test.txt""r", stdin);
113     #else
114     SetFile(cqoi15_network);
115     #endif
116     #ifdef USEFREAD
117     fread(ptr,1,InputLen,stdin);
118     #endif
119     init();
120     Dij();
121     LL ans = 0;
122     while(bfs())
123         ans += dfs(S, INF);
124     printf("%lld\n", ans);
125 #ifdef DEBUG
126     printf("\n%.3lf sec \n", (double)clock() / CLOCKS_PER_SEC);
127 #endif
128     return 0;
129 }
dijkstra+dinic

相关文章: