“玲珑杯”ACM比赛 Round #13 题解&源码

时间:2022-05-07
本文章向大家介绍“玲珑杯”ACM比赛 Round #13 题解&源码,主要内容包括A、B、C、D、E、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

A

题目链接:http://www.ifrog.cc/acm/problem/1111

分析:容易发现本题就是排序不等式, 将A数组与B数组分别排序之后, 答案即N∑i=1Ai×Bi

此题有坑,反正据我提交而言,一直RE,之后发现两个地方会出错,一是定义数组要放在main函数之前,第二是ans+=1LL*a[i]*b[i],如果少了1LL,结果肯定WA,这就是此题的亮点所在!

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std ;
 4 
 5 typedef long long LL ;
 6 
 7 const int MAXN = 500010 ;
 8 
 9 int n ; 
10 
11 int a[MAXN], b[MAXN] ; 
12 
13 int main() { 
14         scanf("%d", &n) ;
15         for (int i = 1; i <= n; i ++) scanf("%d", &a[i]) ; 
16         for (int i = 1; i <= n; i ++) scanf("%d", &b[i]) ;
17         sort(a + 1, a + n + 1) ;
18         sort(b + 1, b + n + 1) ; 
19         LL ans = 0 ; 
20         for (int i = 1; i <= n; i ++) ans += 1LL * a[i] * b[i] ; 
21         cout << ans << endl ; 
22 }

B

题目链接:http://www.ifrog.cc/acm/problem/1112

分析:

一个显然的想法是每一次二分加入到第几个数的时候, 混乱度超过M, 然后暴力检验, 复杂度显然可以是O(N2logN)

级别

我们可以换一种二分方式

令当前左端点为L

, 我们先找到一个最小的K, 使得[L,L+2K)这个区间混乱度超过M

然后右端点在[L+2K−1,L+2K)

中二分即可

考虑每删去至少2K−1

个数, 所需要的时间复杂度最大为O(2KKlogN)

故总复杂度为O(Nlog2N)

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std ;
 4 
 5 int n ;
 6 
 7 typedef long long LL ; 
 8 
 9 LL M ; 
10 
11 const int MAXN = 300010 ;
12 
13 int a[MAXN] ; 
14 
15 int ps[MAXN], p[MAXN], cnt[MAXN], v[MAXN]; 
16 bool vis[MAXN] ; 
17 
18 
19 bool check(int l, int r) { 
20         for (int i = l; i <= r; i ++) p[i] = a[i] ;  
21         sort(p + l, p + r + 1) ; 
22         LL ans = 0 ; 
23         for (int i = l; i <= r; i ++) { 
24                 ans += 1LL * p[i] * v[i - l + 1] ; 
25         }
26         return ans <= M ; 
27 }
28 
29 int main() { 
30         cin >> n >> M ; 
31         for (int i = 1; i <= n; i ++) scanf("%d", &a[i]) ;
32         for (int i = 1; i <= n; i ++) scanf("%d", &v[i]) ;     
33         int l = 1, r = 1 ; 
34         for (; l <= n;) { 
35                  int last = 1, lastp = r - 1 ;  
36                  for (; check(l, r) && lastp < r; lastp = r , r = min(n, r + last), last <<= 1) ; 
37                  if (lastp == r) break ; 
38                  int lp = lastp + 1, rp = r ; 
39                  while (lp < rp) { 
40                          int mid = ((lp + rp) >> 1) ; 
41                          if (!check(l, mid)) rp = mid ;
42                          else lp = mid + 1;  
43                  }
44                  cnt[lp] ++ ; 
45                  l = lp + 1, r = l  ; 
46         }
47         for (int i = 1; i <= n; i ++) {
48                 cnt[i] += cnt[i - 1] ; 
49                 printf("%d", cnt[i]) ; 
50                 if (i < n) putchar(' ') ; 
51         }
52         putchar(10) ; 
53 }

C

题目链接:http://www.ifrog.cc/acm/problem/1113

分析:

注意到, K条路径两两相交的充要条件是这K

条路径有一段公共路径。

对于一条路径, 点数-边数恒为1

所以我们可以算出所有可能的情况中, K

条路径的公共点的个数 减去K

条路径的公共边的条数, 即为答案

我们可以枚举每一个点以及每一条边的贡献, 对于一个点来说, 它的贡献就是所有经过它的路径条数的K

次方,边同理

复杂度O(NlogK)

, 瓶颈在于快速幂

 1 #include <bits/stdc++.h>
 2 
 3 #define MOD 1000000007
 4 
 5 #ifdef WIN32
 6 #define LLD "%I64d"
 7 #else
 8 #define LLD "%lld"
 9 #endif
10 
11 using namespace std ;
12 
13 int n, K ; 
14 
15 typedef long long LL ; 
16 
17 int qpow(int a, int b) { 
18         int ret = 1 ;
19         for (; b; b >>= 1, a = 1LL * a * a % MOD) if (b & 1) ret = 1LL * ret * a % MOD ; 
20         return ret ;
21 }
22 
23 const int MAXN = 500010 ; 
24 
25 int siz[MAXN], fa[MAXN];  
26 
27 vector<int> g[MAXN]; 
28                 
29 int main() { 
30         scanf("%d%d", &n, &K) ; 
31         for (int i = 2; i <= n; i ++) scanf("%d", &fa[i]) ; 
32         for (int i = n; i; i --) {
33                  siz[i] ++ ; 
34                  siz[fa[i]] += siz[i] ; 
35                  g[fa[i]].push_back(i) ; 
36         }
37         int ans = 0 ; 
38         for (int i = 2; i <= n; i ++) { 
39                 int t = 1LL * siz[i] * (n - siz[i]) % MOD ; 
40                 ans = (ans - qpow(t, K) + MOD) % MOD ; 
41         }
42         for (int i = 1; i <= n; i ++) { 
43                 int t = 0 ;
44                 for (int j = 0; j < g[i].size(); j ++) { 
45                         t += 1LL * siz[g[i][j]] * (n - siz[g[i][j]] - 1) % MOD ; 
46                         t %= MOD ; 
47                 }
48                 t += 1LL * (siz[i] - 1) * (n - siz[i]) % MOD ; 
49                 t %= MOD; 
50                 t = 1LL * t * ((MOD + 1) / 2) % MOD ; 
51                 t += n ; 
52                 t %= MOD ; 
53                 ans += qpow(t, K) ;
54                 ans %= MOD ; 
55         }
56         printf("%dn", ans) ; 
57 }    

D

题目链接:http://www.ifrog.cc/acm/problem/1114

分析:

记SMN 为左边N个点, 右边M

个点的完全二分图生成树个数

答案即SKN−K×(N−1K−1)

, 证明显然, 因为把树上的点按照奇偶分层,即得到一个二分图, 每一棵树都对应了这个完全二分图的一个生成树

SMN=NM−1×MN−1

, 暴力用Matrix−Tree可以消元得到这个结论。

 1 #include <bits/stdc++.h>
 2 
 3 #define MOD 998244353
 4 
 5 using namespace std ;
 6 
 7 int n, k; 
 8 
 9 int qpow(int a, int b) { 
10         int ret = 1; 
11         for (; b; b >>= 1, a = 1LL * a * a % MOD) if (b & 1) ret = 1LL * ret * a % MOD ; 
12         return ret ;
13 }
14 
15 int C(int n, int m) { 
16         int ans = 1 ; 
17         for (int i = 1; i <= m; i ++) { 
18                 ans = 1LL * ans * (n - i + 1) % MOD * qpow(i, MOD - 2) % MOD ; 
19         }
20         return ans ;
21 }
22                         
23 int main() { 
24 
25         scanf("%d%d", &n, &k) ; 
26         n -= k ; 
27         int ans = 1LL * qpow(n, k - 1) * qpow(k, n - 1) % MOD ;
28         ans = 1LL * ans * C(n + k - 1, k - 1) % MOD ; 
29         printf("%dn", ans) ; 
30 }

E

题目链接:http://www.ifrog.cc/acm/problem/1115

分析:

  1 #define OPENSTACK
  2 
  3 #include <bits/stdc++.h>
  4 #define MAXN 100010
  5 #define Q 322
  6 #define INF ~0ULL
  7 
  8 using namespace std;
  9 
 10 int n , m , cnt , a[ MAXN ] , tag[ MAXN ] , caocoacao[ MAXN ] , up[ MAXN ] , vis[ MAXN ];
 11 int gandan [ MAXN ] , fa[ MAXN ] , size[ MAXN ] , son[ MAXN ] , xxxxxx[ MAXN ];
 12 unsigned char left_bit[65536] , ssssssss[65536];
 13 unsigned int wocaonimabis[31][ MAXN ] , f[31][65536] , lastans;
 14 
 15 struct wocaonima
 16 {
 17     unsigned long long bit[470];
 18     void clear()
 19     {
 20         memset( bit , 0 , sizeof( bit ) );
 21     }
 22     void operator |= ( const wocaonima & rhs )
 23     {
 24         for( register int i = 0 ; i <= 469 ; i++ )
 25             bit[i] |= rhs.bit[i];
 26     }
 27     void operator |= (const int x)
 28     {
 29         bit[x >> 6] |= 1ll << ( x & 63 );
 30     }
 31     inline int find( unsigned char k )
 32     {
 33         int len = 0 , v[4];
 34         register unsigned int x = 0;
 35         for( register int i = 0 ; i <= 469 ; i++ )
 36         {
 37             v[0] = bit[i] & 65535 , v[1] = ( bit[i] >> 16 ) & 65535 , v[2] = ( bit[i] >> 32 ) & 65535 , v[3] = ( bit[i] >> 48 );
 38             for( register char j = 0 ; j <= 3 ; j++ )
 39                 if( v[j] == 65535 ) len += 16;
 40                 else
 41                 {
 42                     //if( len + left_bit[ v[j] ] ) cerr << " " << len + left_bit[ v[j] ] << endl;
 43                     x += wocaonimabis[k][ len + left_bit[ v[j] ] ];
 44                     x += f[k][ v[j] ];
 45                     len = ssssssss[ v[j] ];
 46                 }
 47         }
 48         return x;
 49     }
 50 } ans;
 51 
 52 wocaonima BIT[Q + 5][Q + 5];
 53 vector < int > linker[ MAXN ];
 54 
 55 #define cur linker[x][i]
 56 
 57 void dfs1( int x )
 58 {
 59     size[x] = 1;
 60     for( int i = 0 ; i < linker[x].size() ; i++ )
 61         if( cur != fa[x] )
 62         {
 63             fa[ cur ] = x , gandan [ cur ] = gandan [x] + 1;
 64             dfs1( cur ) , size[x] += size[ cur ];
 65             if( size[ cur ] > size[ son[x] ] ) son[x] = cur;
 66         }
 67 }
 68 
 69 void dfs2( int x , int t )
 70 {
 71     xxxxxx[x] = t;
 72     if( son[x] ) dfs2( son[x] , t );
 73     for( int i = 0 ; i < linker[x].size() ; i++ )
 74         if( cur != fa[x] && cur != son[x] )
 75             dfs2( cur , cur );
 76 }
 77 
 78 inline int lca( int a , int b )
 79 {
 80     while( xxxxxx[a] != xxxxxx[b] )
 81     {
 82         if( gandan [ xxxxxx[a] ] < gandan [ xxxxxx[b] ] ) swap( a , b );
 83         a = fa[ xxxxxx[a] ];
 84     }
 85     return gandan [a] < gandan [b] ? a : b;
 86 }
 87 
 88 #undef cur
 89 
 90 struct io
 91 {
 92     char ibuf[1 << 23] , * s , obuf[1 << 20] , * t;
 93     int a[24];
 94     io() : t( obuf )
 95     {
 96         fread( s = ibuf , 1 , 1 << 23 , stdin );
 97     }
 98     ~io()
 99     {
100         fwrite( obuf , 1 , t - obuf , stdout );
101     }
102     inline int read()
103     {
104         register int u = 0;
105         while( * s < 48 ) s++;
106         while( * s > 32 )
107             u = u * 10 + * s++ - 48;
108         return u;
109     }
110     template < class T >
111     inline void print( T u , int v )
112     {
113         print( u );
114         * t++ = v;
115     }
116     template< class T >
117     inline void print( register T u )
118     {
119         static int * q = a;
120         if( !u ) * t++ = 48;
121         else
122         {
123             if( u < 0 )
124                 * t++ = 45 , u *= -1;
125             while( u ) * q++ = u % 10 + 48 , u /= 10;
126             while( q != a )
127                 * t++ = * --q;
128         }
129     }
130 } ip;
131 
132 #define read ip.read
133 #define print ip.print
134 
135 inline void addedge( int x , int y )
136 {
137     linker[x].push_back( y );
138     linker[y].push_back( x );
139 }
140 
141 int main()
142 {
143     #ifdef OPENSTACK
144         int size = 64 << 20; // 64MB
145         char *p = (char*)malloc(size) + size;
146         #if (defined _WIN64) or (defined __unix)
147             __asm__("movq %0, %%rspn" :: "r"(p));
148         #else
149             __asm__("movl %0, %%espn" :: "r"(p));
150         #endif
151     #endif
152     srand( time( 0 ) );
153     for( int s = 0 ; s < 65536 ; s++ )
154     {
155         left_bit[s] = ssssssss[s] = 16;
156         for( register int i = 0 ; i < 16 ; i++ )
157             if( !( ( s >> i ) & 1 ) )
158             {
159                 left_bit[s] = i;
160                 break;
161             }
162         for( register int i = 15 ; ~i ; i-- )
163             if( !( ( s >> i ) & 1 ) )
164             {
165                 ssssssss[s] = 15 - i;
166                 break;
167             }
168     }
169     n = read() , m = read();
170     for( int i = 0 ; i <= n ; i++ )
171         for( register int j = wocaonimabis[0][i] = 1 ; j <= 30 ; j++ )
172             wocaonimabis[0][0] = 0 , wocaonimabis[j][i] = wocaonimabis[j - 1][i] * i;
173     for( int j = 0 ; j <= 30 ; j++ )
174         for( int s = 0 ; s < 65536 ; s++ )
175         {
176             int len = 0;
177             for( register int i = left_bit[s] + 1 ; i <= 15 - ssssssss[s] ; i++ )
178                 if( ( s >> i ) & 1 ) len++;
179                 else f[j][s] += wocaonimabis[j][ len ] , len = 0;
180             if( len ) f[j][s] += wocaonimabis[j][ len ];
181         }
182     for( register int i = 1 ; i <= n ; i++ ) a[i] = read();
183     for( register int i = 1 ; i < n ; i++ ) addedge( read() , read() );
184     dfs1( 1 ) , dfs2( 1 , 1 );
185     for( int i = 1 ; i <= min( n , Q ) ; i++ )
186     {
187         int pos;
188         while( vis[ pos = rand() * rand() % n + 1 ] );
189         vis[ pos ] = 1 , tag[i] = pos , caocoacao[ tag[i] ] = i;
190     }
191     for( int i = 1 ; i <= min( n , Q ) ; i++ )
192     {
193         int cur = tag[i];
194         ans.clear();
195         do
196         {
197             ans |= a[ cur ];
198             if( cur != tag[i] && caocoacao[cur] ) 
199             {
200                 BIT[i][ caocoacao[ cur ] ] |= ans;
201                 if( !up[ tag[i] ] )
202                     up[ tag[i] ] = cur;
203             }
204             cur = fa[ cur ];
205         }
206         while( cur );
207     }
208     for( int i = 1 ; i <= m ; i++ )
209     {
210         int cnt = read();
211         ans.clear();
212         for( int j = 1 ; j <= cnt ; j++ )
213         {
214             int x = read() ^ lastans , y = read() ^ lastans , z = lca( x , y );
215             ans |= a[z];
216             while( !caocoacao[x] && x != z )
217             {
218                 ans |= a[x];
219                 x = fa[x];
220             }
221             int now = x;
222             while( gandan [ up[x] ] > gandan [z] ) x = up[x];
223             ans |= BIT[ caocoacao[ now ] ][ caocoacao[x] ];
224             while( x != z )
225             {
226                 ans |= a[x];
227                 x = fa[x];
228             }
229             while( !caocoacao[y] && y != z )
230             {
231                 ans |= a[y];
232                 y = fa[y];
233             }
234             now = y;
235             while( gandan [ up[y] ] > gandan [z] ) y = up[y];
236             ans |= BIT[ caocoacao[ now ] ][ caocoacao[y] ];
237             while( y != z )
238             {
239                 ans |= a[y];
240                 y = fa[y];
241             }
242         }
243         print( lastans = ans.find( read() ) , 'n' );
244     }
245     #ifdef OPENSTACK
246         exit(0);
247     #else
248         return 0;
249     #endif
250     return 0;
251 }