AtCoder ZONe Energy Programming Contest 题解


ZONe Energy Programming Contest

A - UFO Invasion

太简单了。

#include <cstdio>
char ch[10] = { 'Z', 'O', 'N', 'e' };
char s[20];

int main() {
	scanf( "%s", s );
	int tot = 0, idx = 0;
	for( int i = 0;i < 12;i ++ ) {
		if( s[i] == ch[idx] ) {
			idx ++;
			if( idx == 4 ) {
				tot ++;
				idx = 0;
			}else;
		} 
		else 
			idx = ( s[i] == ch[0] );
	}
	printf( "%d", tot );
	return 0;
}

B - Sign of Friendship

就是斜率问题。

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 105
double d[maxn], h[maxn];
int n;
double D, H;

int main() {
	scanf( "%d %lf %lf", &n, &D, &H );
	for( int i = 1;i <= n;i ++ )
		scanf( "%lf %lf", &d[i], &h[i] );
	double ans = 0;
	for( int i = 1;i <= n;i ++ )
		ans = max( ans, H - D * ( ( H - h[i] ) / ( D - d[i] ) ) );
	printf( "%f\n", ans );
	return 0;
}

C - MAD TEAM

二分最后的答案,利用二进制

如果第 i i i个的第 j j j个属性大于答案,设为 1 1 1,否则为 0 0 0

最后相当于找三个二进制串或起来填满了二进制五位 2 5 − 1 = 31 2^5-1=31 251=31

#include <cstdio>
#include <set>
using namespace std;
#define maxn 3005
set < int > st;
int n;
int p[maxn][5];

bool check( int x ) {
	st.clear();
	for( int i = 1;i <= n;i ++ ) {
		int t = 0;
		for( int j = 0;j < 5;j ++ ) {
			t <<= 1;
			t += ( p[i][j] >= x );
		}
		st.insert( t );
	}
	for( set < int > :: iterator i = st.begin();i != st.end();i ++ )
		for( set < int > :: iterator j = st.begin();j != st.end();j ++ )
			for( set < int > :: iterator k = st.begin();k != st.end();k ++ )
				if( ( (*i) | (*j) | (*k) ) == 31 ) return 1;
	return 0;
}
 
int main() {
	scanf( "%d", &n );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d %d %d %d %d", &p[i][0], &p[i][1], &p[i][2], &p[i][3], &p[i][4] );
	int l = 0, r = 1e9, ans;
	while( l <= r ) {
		int mid = ( l + r ) >> 1;
		if( check( mid ) ) ans = mid, l = mid + 1;
		else r = mid - 1;
	}
	printf( "%d\n", ans );
	return 0;
}

D - Message from Aliens

考虑以R作为分界点,不妨改写原串1R2R3R4...(1,2,3,4代表一个整字符串,可以为空)

定义 1 ‾ \overline{1} 1 表示翻转字符串1

手玩一下会发现,答案的长相只与R个数的奇偶性有关

  • 个数为奇数, 3 ‾ 1 ‾ 24 \overline{3}\overline{1}24 3124

    奇数串翻转从大到小,偶数串从小到大

  • 个数为偶数, 4 ‾ 2 ‾ 135 \overline{4}\overline{2}135 42135

    偶数串翻转从大到小,奇数串从小到大

定义一个整体翻转标记 f l a g flag flag

既可以加在前面又可以加在后面的操作用deque实现

最后连续相同的字符需要删掉。就进行判断,如果即将要入队的字符与已加入的最后一个相同就都扔掉,再定义一个队列操作即可

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define maxn 500005
deque < char > q, ans;
char s[maxn];

int main() {
	scanf( "%s", s );
	int len = strlen( s ); bool flag = 0;
	for( int i = 0;i < len;i ++ ) {
		if( s[i] == 'R' ) flag ^= 1;
		else
			if( flag ) q.push_front( s[i] );
			else q.push_back( s[i] );
	}
	if( flag ) reverse( q.begin(), q.end() );
	while( ! q.empty() ) {
		if( ! ans.empty() && ans.back() == q.front() ) q.pop_front(), ans.pop_back();
		else ans.push_back( q.front() ), q.pop_front();
	}
	while( ! ans.empty() ) printf( "%c", ans.front() ), ans.pop_front();
	return 0;
}

E - Sneaking

建图跑最短路

特殊情况是点可以无限往上飞,这导致边数过大,且 + 1 +1 +1非常不方便

建虚点 i ′ i' i i − i ′ → 1 , i ′ − i → 0 , i ′ − ( i − 1 ) ′ → 1 i-i'\rightarrow1,i'-i\rightarrow 0,i'-(i-1)'\rightarrow 1 ii1,ii0,i(i1)1

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 505
struct node {
	int v, w;
	node(){}
	node( int V, int W ) {
		v = V, w = W;
	}
	bool operator < ( node t ) const {
		return w > t.w;
	}
};
priority_queue < node > q;
vector < node > G[maxn * maxn * 2];
int n, m;
int A[maxn][maxn], B[maxn][maxn];
int dp[maxn * maxn * 2];

void addedge( int u, int v, int w ) {
	G[u].push_back( node( v, w ) );
}

int id( int i, int j ) {
	return ( i - 1 ) * m + j;
}

int main() {
	scanf( "%d %d", &n, &m );
	for( int i = 1;i <= n;i ++ )
		for( int j = 1;j < m;j ++ )
			scanf( "%d", &A[i][j] );
	for( int i = 1;i < n;i ++ )
		for( int j = 1;j <= m;j ++ )
			scanf( "%d", &B[i][j] );
	for( int i = 1;i <= n;i ++ )
		for( int j = 1;j <= m;j ++ ) {
			addedge( id( i, j ), id( i, j ) + n * m, 1 );
			addedge( id( i, j ) + n * m, id( i, j ), 0 );
			if( i > 1 ) addedge( id( i, j ) + n * m, id( i - 1, j ) + n * m, 1 );
			if( i < n ) addedge( id( i, j ), id( i + 1, j ), B[i][j] );
			if( j > 1 ) addedge( id( i, j ), id( i, j - 1 ), A[i][j - 1] );
			if( j < m ) addedge( id( i, j ), id( i, j + 1 ), A[i][j] );
		}
	memset( dp, 0x7f, sizeof( dp ) );
	dp[1] = 0;
	q.push( node( id( 1, 1 ), 0 ) );
	while( ! q.empty() ) {
		node t = q.top(); q.pop();
		int u = t.v, w = t.w;
		if( u == n * m ) return ! printf( "%d\n", w );
		for( int i = 0;i < G[u].size();i ++ ) {
			int v = G[u][i].v, cost = G[u][i].w;
			if( dp[v] > w + cost ) {
				dp[v] = w + cost;
				q.push( node( v, dp[v] ) );
			}
		}
	}
	return 0;
}

F - Encounter and Farewell

S S S为被禁止边权集,其补集为 T T T a → b a\rightarrow b ab相当于异或若干个 T T T内元素,此乃线性基也

有解情况是 [ 1 , N ) [1,N) [1,N)满秩

#include <cmath>
#include <cstdio>
using namespace std;
#define maxn 262200
int N, M, n;
int id[maxn], A[maxn], f[maxn];
bool flag[maxn];

int find( int x ) {
	return x == f[x] ? x : f[x] = find( f[x] );
}

void unionSet( int u, int v ) {
	int fu = find( u ), fv = find( v );
	f[fv] = fu;
}

int main() {
	scanf( "%d %d", &N, &M );
	while( ( 1 << n ) != N ) n ++;
	n --;
	for( int i = 1, x;i <= M;i ++ )
		scanf( "%d", &x ), flag[x] = 1;
	for( int i = 1;i < N;i ++ ) {
		if( flag[i] ) continue;
		int x = i;
		for( int j = n;~ j && x;j -- ) {
			if( x >> j & 1 ) {
				if( ! A[j] ) A[j] = x, id[j] = i;
				x ^= A[j];
			}		
		}
	}
	for( int i = 0;i <= n;i ++ )
		if( ! id[i] ) return ! printf( "-1\n" );
	for( int i = 0;i < N;i ++ ) f[i] = i;
	for( int i = 0;i < N;i ++ )
		for( int j = 0;j <= n;j ++ )
			if( find( i ) != find( i ^ id[j] ) ) {
				unionSet( i, i ^ id[j] );
				printf( "%d %d\n", i, i ^ id[j] );
			} else;
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值