Codeforces Round #285 (Div. 2) ABCD

A题

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 
 7 using namespace std;
 8 
 9 #define LL long long
10 #define eps 1e-8
11 #define inf 0x3f3f3f3f
12 #define mnx 100010
13 
14 int main(){
15     int a, b, c, d;
16     scanf( "%d%d%d%d", &a, &b, &c, &d );
17     int a1 = max( 3 * a / 10, a - a / 250 * c );
18     int a2 = max( 3 * b / 10, b - b / 250 * d );
19     if( a1 > a2 ) puts( "Misha" );
20     else if( a1 == a2 ) puts( "Tie" );
21     else puts( "Vasya" );
22     return 0;
23 }
View Code

B题

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 
 7 using namespace std;
 8 
 9 #define LL long long
10 #define eps 1e-8
11 #define inf 0x3f3f3f3f
12 #define mnx 1010
13 
14 char s[mnx][mnx], ch[mnx][mnx];
15 int main(){
16     int n, m = 0;
17     scanf( "%d", &n );
18     for( int i = 0; i < n; ++i ){
19         cin >> s[m] >> ch[m];
20         bool ok = 1;
21         int j;
22         for( j = 0; j < m; ++j ){
23             if( strcmp( ch[j], s[m] ) == 0 ){ ok = 0; break; }
24         }
25         if( ok ) m++;
26         else strcpy( ch[j], ch[m] );
27     }
28     cout << m << endl;
29     for( int i = 0; i < m; ++i ){
30         cout << s[i] << " " << ch[i] << endl;
31     }
32 }
View Code

C题 傻逼了,想错了。。后来发现把相连的边的数量当做入度,把全部node都塞进优先队列里,每次弹出度数最小的点u。如果访问过或者度数为0,就continue;否则就找到 v = u.val ^ x[u],给v所在节点的入度减1,x[v] ^= u,再把v塞进队列里,同时标记u已经访问过。记录边(u,v)我直接就用了vector

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <queue>
 7 #include <vector>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-8
13 #define inf 0x3f3f3f3f
14 #define mnx 300100
15 
16 vector<int> g[mnx];
17 struct node{
18     int in, val, id;
19     bool operator < ( const node &b ) const {
20         return in > b.in;
21     }
22 }c[mnx];
23 int x[mnx];
24 bool vis[mnx];
25 int main(){
26     int n, m = 0;
27     scanf( "%d", &n );
28     priority_queue<node> q;
29     for( int i = 0; i < n; ++i ){
30         scanf( "%d %d", &c[i].in, &c[i].val );
31         c[i].id = i;
32         q.push( c[i] );
33     }
34     while( !q.empty() ){
35         node kk = q.top(); q.pop();
36         int u = kk.id;
37         if( vis[u] ) continue;
38         vis[u] = 1;
39         if( kk.in == 0 ) continue;
40         int v = kk.val ^ x[u];
41         x[v] ^= u;
42         c[v].in--;
43         q.push( c[v] );
44         g[u].push_back( v );
45         m++;
46     }
47     cout << m << endl;
48     for( int i = 0; i < n; ++i ){
49         int k = g[i].size();
50         for( int j = 0; j < k; ++j )
51             cout << i << " " << g[i][j] << endl;
52     }
53     return 0;
54 }
View Code

D题 看到别人的题解说的 康托展开。果然知识面不够丰富。

如我想知道321是{1,2,3}中第几个小的数可以这样考虑 :

第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个小的数。 2*2!+1*1!+0*0!就是康托展开。

一个全排列 ,可以看成a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!, 那么其实只要处理出每一项的系数,然后把两个序列的系数加起来,然后进行进位操作,就可以求出答案的每一项的系数。求系数实际上就是求后面有多少个数是小于这个数的。这个过程要利用树状数组来维护。

求出答案的系数后,再二分找答案(开始的时候一直都写不对这个二分,后来看了题解的二分,发现自己有智商捉急了)。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <queue>
 7 #include <vector>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-8
13 #define inf 0x3f3f3f3f
14 #define mnx 300100
15 
16 int p[mnx], q[mnx], bit[mnx], n;
17 int sum( int x ){
18     int ret = 0;
19     while( x > 0 ){
20         ret += bit[x];
21         x -= x & -x;
22     }
23     return ret;
24 }
25 void add( int i, int x ){
26     while( i <= n ){
27         bit[i] += x;
28         i += i & -i;
29     }
30 }
31 int main(){
32     scanf( "%d", &n );
33     for( int i = 1; i <= n; ++i ){
34         scanf( "%d", &p[i] );
35         int tmp = sum( p[i] );
36         q[i] += p[i] - tmp;
37         add( p[i] + 1, 1 );
38     }
39     memset( bit, 0, sizeof( bit ) );
40     for( int i = 1; i <= n; ++i ){
41         scanf( "%d", &p[i] );
42         int tmp = sum( p[i] );
43         q[i] += p[i] - tmp;
44         add( p[i] + 1, 1 );
45     }
46     for( int i = n; i > 0; --i )
47         if( q[i] >= ( n - i + 1) ){
48             q[i-1] += q[i] / ( n - i + 1 );
49             q[i] %= ( n - i + 1);
50         }
51     memset( bit, 0, sizeof( bit ) );
52     for( int i = 1; i <= n; ++i ) add( i, 1 );
53     for( int i = 1; i <= n; ++i ){
54         int l = 1, r = n;
55         while( l < r ){
56             int mid = ( l+r ) >> 1;        设q[i] = 2, mid = 4, 数字2已经用了。
57             int tmp = sum( mid );          假设4还没有用,这时tmp = 3, tmp - 1 == 2 == q[i], 4应该是右端点
58             if( tmp - 1 < q[i] )           假设4已经用了,这时tmp = 2, tmp - 1 == 1 < q[i], 此时5应该是左端点
59                 l = mid + 1;
60             else r = mid;
61         }
62         cout << l - 1 << " ";
63         add( l, -1 );
64     }
65     return 0;
66 }
View Code
原文地址:https://www.cnblogs.com/LJ-blog/p/4230015.html