A题逗比了,没有看到All ai are distinct. All bi are distinct. 其实很水的。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define mnx 100002 8 9 10 struct latop{ 11 int p, q; 12 bool operator < ( const latop & b ) const { 13 return p < b.p; 14 } 15 }a[mnx]; 16 int main(){ 17 int n; 18 scanf( "%d", &n ); 19 for( int i = 0; i < n; i++ ){ 20 scanf( "%d %d", &a[i].p, &a[i].q ); 21 } 22 sort( a, a + n ); 23 bool flag = 0; 24 for( int i = 1; i < n; i++ ){ 25 if( a[i].q < a[i-1].q ) flag = 1; 26 } 27 if( flag ) puts( "Happy Alex" ); 28 else puts( "Poor Alex" ); 29 return 0; 30 }
B题找循环节。。循环节是4,然后输入再长的数,也只需要看最后两位,因为100的倍数肯定能够整除4,就看最后两位。。结果又逗比了,数组开小了,最后re了。。太粗心了。。
1 #include<string> 2 #include<cmath> 3 #include<map> 4 #include<queue> 5 6 using namespace std; 7 8 #define mnx 1000000 9 #define PI acos(-1.0) 10 #define ll long long 11 #define ull unsigned long long 12 #define inf 0x3f3f3f3f 13 #define eps 1e-8 14 #define MP make_pair 15 #define lson l, m, rt << 1 16 #define rson m+1, r, rt << 1 | 1 17 #define mod 2333333 18 19 int a[4] = { 4, 0, 0, 0 }; 20 char ch[mnx]; 21 int main(){ 22 scanf( "%s", &ch ); 23 int n = strlen( ch ); 24 int k = 0; 25 if( n <= 2 ){ 26 for( int i = 0; i < n; i++ ){ 27 k = k * 10 + ch[i] - '0'; 28 } 29 // cout<<k<<endl; 30 k %= 4; 31 printf( "%d ", a[k] ); 32 } 33 else{ 34 for( int i = n-2; i < n; i++ ){ 35 k = k * 10 + ch[i] - '0'; 36 } 37 // cout<<k<<endl; 38 k %= 4; 39 printf( "%d ", a[k] ); 40 } 41 return 0; 42 }
C题先排序,然后把相同的弄掉,if( b[i] == b[i-1] + 1 ) dp[i] = max( dp[i-2] + sum[i], dp[i-1] ),要么就是选当前这个b[i],然后dp[i]的值就是dp[i-2] + sum[i],要么就选b[i-1],然后dp[i]的值就是dp[i-1];else dp[i] = dp[i] = dp[i-1] + sum[i]; 最后答案就是 dp[cnt]; 具体看代码。。当时写的比较稳妥,多写了一些。。结果还是因为longlong跪了几发,这是后来写的代码
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<string> 6 #include<cmath> 7 #include<map> 8 #include<queue> 9 10 using namespace std; 11 12 #define mnx 200000 13 #define PI acos(-1.0) 14 #define ll long long 15 #define ull unsigned long long 16 #define inf 0x3f3f3f3f 17 #define eps 1e-8 18 #define MP make_pair 19 #define lson l, m, rt << 1 20 #define rson m+1, r, rt << 1 | 1 21 #define mod 2333333 22 23 ll a[mnx], b[mnx], sum[mnx], dp[mnx]; 24 int main(){ 25 int n; 26 scanf( "%d", &n ); 27 for( int i = 1; i <= n; i++ ){ 28 scanf( "%I64d", &a[i] ); 29 } 30 sort( a + 1, a + 1 + n ); 31 int cnt = 0; 32 for( int i = 1; i <= n; i++ ){ 33 if( a[i] != b[cnt] ){ 34 ++cnt; 35 b[cnt] = a[i]; 36 sum[cnt] = a[i]; 37 } 38 else sum[cnt] += a[i]; 39 } 40 dp[1] = sum[1]; 41 for( int i = 2; i <= cnt; i++ ){ 42 if( b[i] == b[i-1] + 1 ){ 43 dp[i] = max( dp[i-2] + sum[i], dp[i-1] ); 44 } 45 else{ 46 dp[i] = dp[i-1] + sum[i]; 47 } 48 } 49 cout<<dp[cnt]<<endl; 50 return 0; 51 }
D题trie树,不会做。。赛后问了思路,弄了很久才明白。。原本的想法是 trie的根就是必败,然后dfs,第一层就是必胜,遍历到叶子节点,看叶子节点是必败还是必胜,如果叶子节点全是必胜的,说明先手的每次必胜,如果叶子节点全是必败的,说明先手的每次必败,如果叶子节点既有必胜又有必败的,说明先手的每次既能必胜也能必败。。后来发现这样想是错的,如果是abcs,abcab,先手走到c,接下来先手的输赢全部是由后手决定,后手走s,先手输,后手走a,先手赢。。这道题输赢的状态必须由叶子节点开始向根的方向推,看了超哥的代码,开两个bool数组,win[], can[],win数组表示下一步先手开始走,能不能赢,can数组表示下一步先手开始走,能不能输。。所以叶子节点就是win[u] = 0(先手下一步不能走,就不能赢),can[u] = 1(先手下一步不能走,肯定输)。。当一个节点有多个子节点,win[u] = 1就看 win[son[u][i]]里面有没有为0的,否则就是0;can[u] = 1就看can[son[u][i]]里面有没有为0的,否则就是0。。推到根节点的状态。。这样讲有点抽象,可以手动模拟一下 abcs, abcab这种情况。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define mnx 100002 8 9 int son[mnx][26], tot; 10 bool win[mnx], can[mnx]; 11 void insert(char *s) { 12 int t = 0; 13 for (int i = 0; s[i]; ++i) { 14 int c = s[i] - 'a'; 15 if (!son[t][c]) son[t][c] = ++tot; 16 t = son[t][c]; 17 } 18 } 19 void dfs( int u ){ 20 win[u] = 0, can[u] = 1; 21 bool hav = 0; 22 for( int i = 0; i < 26; i++ ){ 23 if( son[u][i] ){ 24 dfs( son[u][i] ); hav = 1; 25 } 26 } 27 if( !hav ) return ; 28 can[u] = 0; 29 for( int i = 0; i < 26; i++ ){ 30 if( son[u][i] && !win[son[u][i]] ) win[u] = 1; 31 if( son[u][i] && !can[son[u][i]] ) can[u] = 1; 32 } 33 } 34 char ch[mnx]; 35 int main(){ 36 int n, k; 37 scanf( "%d%d", &n, &k ); 38 for( int i = 0; i < n; i++ ){ 39 scanf( "%s", ch ); 40 insert( ch ); 41 } 42 dfs( 0 ); 43 if( win[0] == false ) puts( "Second" ); 44 else{ 45 if( can[0] == true ) puts( "First" ); 46 else puts( (k & 1) ? "First" : "Second" ); 47 } 48 return 0; 49 }
E题没时间看,赛后看了一下,发现也不是很难,树的直径和并查集。。比较难处理的就是connect them by a road so as to minimize the length of the longest path in the resulting region 使联通后的区域的直径最小,那么就应该从两条直径的中间点连一条边,使他们联通。。假设要联通两个区域为u,v,直径为val[u], val[v],则联通后的直径应该是 max( val[u], val[v], 1 + ( val[u] - val[u] / 2 ) + ( val[v] - val[v] / 2 );
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define mnx 600005 8 #define inf 0x3f3f3f3f 9 10 int dis[2][mnx], fa[mnx], val[mnx]; 11 int vv[mnx], first[mnx], nxt[mnx], e; 12 bool vis[mnx], in[mnx]; 13 int n, m, query, tot; 14 void init(){ 15 memset( first, -1, sizeof(first) ); 16 memset( dis, 0x3f, sizeof(dis) ); 17 e = 0; 18 } 19 void add( int u, int v ){ 20 vv[e] = v, nxt[e] = first[u], first[u] = e++; 21 } 22 int q[mnx]; 23 int bfs( int s, int *dis ){ 24 int head = 0, tail = 0; 25 q[tail++] = s, dis[s] = 0; 26 while( head < tail ){ 27 int u = q[head++]; 28 vis[u] = 1; 29 for( int i = first[u]; i != -1; i = nxt[i] ){ 30 int v = vv[i]; 31 if( dis[v] > dis[u] + 1 ){ 32 dis[v] = dis[u] + 1; 33 q[tail++] = v; 34 } 35 } 36 } 37 int id = s, d = dis[s]; 38 for( int i = 0; i < tail; i++ ){ 39 if( dis[q[i]] > d ){ 40 d = dis[q[i]], id = q[i]; 41 } 42 } 43 return id; 44 } 45 int find( int s ){ 46 if( s != fa[s] ){ 47 fa[s] = find( fa[s] ); 48 } 49 return fa[s]; 50 } 51 void treeD( int s ){ 52 int v = bfs( s, dis[0] ); 53 int u = bfs( v, dis[1] ); 54 val[find(u)] = dis[1][u]; 55 } 56 int main(){ 57 scanf( "%d %d %d", &n, &m, &query ); 58 tot = n; 59 init(); 60 for( int i = 0; i <= n + query; i++ ){ 61 fa[i] = i; 62 } 63 while( m-- ){ 64 int u, v; 65 scanf( "%d %d", &u, &v ); 66 add( u, v ), add( v, u ); 67 int fu = find( u ), fv = find( v ); 68 fa[fu] = fv; 69 } 70 for( int i = 1; i <= n; i++ ){ 71 if( !vis[i] ){ 72 treeD( i ); 73 } 74 } 75 while( query-- ){ 76 int tye, u, v; 77 scanf( "%d", &tye ); 78 if( tye == 1 ){ 79 scanf( "%d", &u ); 80 printf( "%d ", val[find(u)] ); 81 } 82 else{ 83 scanf( "%d%d", &u, &v ); 84 int fu = find( u ), fv = find( v ); 85 if( fu == fv ) continue; 86 ++tot; 87 fa[fu] = fa[fv] = tot; 88 val[tot] = 1 + ( val[fu] - val[fu] / 2 ) + ( val[fv] - val[fv] / 2 ); 89 val[tot] = max( val[tot], val[fu] ); 90 val[tot] = max( val[tot], val[fv] ); 91 } 92 } 93 return 0; 94 }