[AtCoder Beginner Contest 215] A-G题解

atcoder题目链接

A - Your First Judge

签到题

#include <cstdio>
#include <iostream>
using namespace std;
string s;
int main() {
	cin >> s;
	if( s == "Hello,World!" ) printf( "AC\n" );
	else printf("WA\n" );
	return 0;
}

B - log2(N)

签到题

#include <cstdio>
int main() {
	long long n;
	scanf( "%lld", &n );
	int ans;
	for( int i = 0;;i ++ ) {
		if( ( 1ll << i ) <= n ) ans = i;
		else break;
	}
	printf( "%d", ans );
	return 0;
}

C - One More aab aba baa

离散化后压成整数搜索,简单题

#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
stack < char > sta;
char s[10], rnk[10];
int t[40325], used[30];
bool vis[10];
int n, k, cnt, tot;

void dfs( int x, int val ) {
	if( x > n ) {
		t[++ cnt] = val;
		return;
	}
	for( int i = 1;i <= n;i ++ )
		if( vis[i] ) continue;
		else {
			vis[i] = 1;
			dfs( x + 1, val * 10 + used[s[i] - 'a' + 1] );
			vis[i] = 0;
		}
}

int main() {
	scanf( "%s %d", s + 1, &k );
	n = strlen( s + 1 );
	for( char i = 'a';i <= 'z';i ++ )
		for( int j = 1;j <= n;j ++ )
			if( s[j] == i ) {
				used[i - 'a' + 1] = ++ tot, rnk[tot] = i;
				break;
			}
	dfs( 1, 0 );
	sort( t + 1, t + cnt + 1 );
	cnt = unique( t + 1, t + cnt + 1 ) - t - 1;
	while( t[k] ) sta.push( rnk[t[k] % 10] ), t[k] /= 10;
	while( ! sta.empty() ) printf( "%c", sta.top() ), sta.pop();
	return 0;
}

D - Coprime 2

质因数分解后,把质因数的倍数都筛掉,简单题

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 100005
vector < int > ans;
int cnt;
bool vis[maxn], is[maxn];
int prime[maxn];

void init( int n ) {
	for( int i = 2;i <= n;i ++ ) {
		if( ! vis[i] ) is[i] = 1, prime[++ cnt] = i;
		for( int j = 1;j <= cnt && i * prime[j] <= n;j ++ ) {
			vis[i * prime[j]] = 1;
			if( i % prime[j] == 0 ) break;
		}
	}
}

int n, m;
int a[maxn], p[maxn * 100];

int main() {
	init( 1e5 );
	scanf( "%d %d", &n, &m );
	for( int i = 1;i <= n;i ++ )
		scanf( "%d", &a[i] );
	cnt = 0;
	for( int i = 1;i <= n;i ++ ) {
		for( int j = 1;j * j <= a[i];j ++ )
			if( a[i] % j == 0 ) {
				if( is[j] ) p[++ cnt] = j;
				if( is[a[i] / j] ) p[++ cnt] = a[i] / j;
			}
	}
	for( int i = 1;i <= m;i ++ ) vis[i] = 0;
	sort( p + 1, p + cnt + 1 );
	cnt = unique( p + 1, p + cnt + 1 ) - p - 1;
	for( int i = 1;i <= cnt;i ++ )
		for( int j = p[i];j <= m;j += p[i] )
			vis[j] = 1;
	for( int i = 1;i <= m;i ++ )
		if( ! vis[i] ) ans.push_back( i );
	printf( "%d\n", ans.size() );
	for( int i = 0;i < ans.size();i ++ )
		printf( "%d\n", ans[i] );
	return 0;
}

E - Chain Contestant

只有 10 10 10种,符合状压

d p i , s , j : dp_{i,s,j}: dpi,s,j: i i i为止出现字符的状态为 s s s,上一次出现的字符为 j j j(多加一种字符表示空)

  • 不选 i i i

    d p i , s , j + = d p [ i − 1 ] [ s ] [ j ] dp_{i,s,j}+=dp[i-1][s][j] dpi,s,j+=dp[i1][s][j]

  • i i i,必须满足 i i i位置字符没出现过上一次出现字符就是 i i i位置字符

    d p [ i ] [ 1 < < t [ i ] ∣ s ] [ t [ i ] ] + = d p [ i ] [ 1 < < t [ i ] ∣ s ] [ t [ i ] ] + d p [ i − 1 ] [ s ] [ j ] dp[i][1 << t[i] | s][t[i]]+=dp[i][1 << t[i] | s][t[i]] + dp[i - 1][s][j] dp[i][1<<t[i]s][t[i]]+=dp[i][1<<t[i]s][t[i]]+dp[i1][s][j]

简单题

#include <cstdio>
#define int long long
#define mod 998244353
#define maxn 1002
#define S 1 << 10
int n;
char s[maxn];
int t[maxn];
int dp[maxn][S][11];

signed main() {
	scanf( "%lld %s", &n, s + 1 );
	for( int i = 1;i <= n;i ++ ) t[i] = s[i] - 'A';
	dp[0][0][10] = 1;
	for( int i = 1;i <= n;i ++ )
		for( int sta = 0;sta < S;sta ++ )
			for( int j = 0;j <= 10;j ++ )
				if( ! dp[i - 1][sta][j] ) continue;
				else {
					dp[i][sta][j] = ( dp[i][sta][j] + dp[i - 1][sta][j] ) % mod;
					if( j == 10 ) 
						dp[i][1 << t[i] | sta][t[i]] = ( dp[i][1 << t[i] | sta][t[i]] + dp[i - 1][sta][j] ) % mod;
					else 
						if( ( 1 << t[i] & sta ) and j != t[i] ) continue;
						else
							dp[i][1 << t[i] | sta][t[i]] = ( dp[i][1 << t[i] | sta][t[i]] + dp[i - 1][sta][j] ) % mod;
				}
	int ans = 0;
	for( int i = 0;i < S;i ++ )
		for( int j = 0;j <= 10;j ++ )
			if( i == 0 && j == 10 ) continue;
			else ans = ( ans + dp[n][i][j] ) % mod;
	printf( "%lld\n", ans );
	return 0;
}

F - Dist Max 2

二分答案

将点按 x x x坐标排序

类似滑动窗口模拟

记录在满足 x x x坐标情况下的最大最小 y y y,判断是否有满足与现在枚举 i i i y y y距离不小于二分答案

简单题

#include <queue>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 200005
struct node { int x, y; }p[maxn];
queue < node > q;
int n;

int main() {
	scanf( "%d", &n );
	for( int i = 1;i <= n;i ++ ) scanf( "%d %d", &p[i].x, &p[i].y );
	sort( p + 1, p + n + 1, []( node s, node t ) { return s.x < t.x; } );
	int l = 0, r = 1e9, ans;
	next :
	while( l <= r ) {
		int mid = l + r >> 1;
		while( ! q.empty() ) q.pop();
		int Min = 1e9, Max = 0;
		for( int i = 1;i <= n;i ++ ) {
			while( ! q.empty() ) {
				if( q.front().x > p[i].x - mid ) break;
				Min = min( Min, q.front().y );
				Max = max( Max, q.front().y );
				q.pop();
			}
			if( Min <= p[i].y - mid or Max >= p[i].y + mid ) {
				ans = mid, l = mid + 1;
				goto next;
			}
			q.push( p[i] );
		}
		r = mid - 1;
	}
	printf( "%d\n", ans );
	return 0;
}

G - Colorful Candies 2

中档题

C C C表示不同的糖果颜色数,将 N N N颗糖果重新离散化颜色1,2,...,C

显然答案与具体糖果的颜色无关,只与每种颜色的个数有关,令 n i n_i ni表示颜色为 i i i的糖果个数

枚举每一轮要选择的糖果个数 K K K

对于每一种颜色,定义 X i X_i Xi,若选择糖果种有 i i i颜色, X i = 1 X_i=1 Xi=1,否则 X i = 0 X_i=0 Xi=0

K K K糖果中不同颜色种数可以表示为 ∑ i = 1 C X i \sum_{i=1}^CX_i i=1CXi

所求期望为 E [ ∑ i = 1 C X i ] E\Big[\sum_{i=1}^CX_i\Big] E[i=1CXi],根据期望的线性可加性知道 = ∑ i = 1 C E [ X i ] =\sum_{i=1}^CE\Big[X_i\Big] =i=1CE[Xi]

一个颜色出现的期望很简单,出现的方案数 / / /总方案数,出现的方案数 = = =总方案数 − - 一次都没出现
E [ X i ] = ( N K ) − ( N − n i K ) ( N K ) E\Big[X_i\Big]=\frac{\binom{N}{K}-\binom{N-n_i}{K}}{\binom{N}{K}} E[Xi]=(KN)(KN)(KNni)
枚举 i i i又是 O ( n ) O(n) O(n)的时间,再加上外层的 K K K枚举,时间 O ( n 2 ) O(n^2) O(n2)难以接受

发现其实如果有 x x x种颜色的个数都是 n i n_i ni,那么这 x x x种颜色的期望可以 O ( 1 ) O(1) O(1)计算
x ∗ ( N K ) − ( N − n i K ) ( N K ) x*\frac{\binom{N}{K}-\binom{N-n_i}{K}}{\binom{N}{K}} x(KN)(KN)(KNni)
那么不同个数就是 n i = 1 , 2 , . . . , n_i=1,2,..., ni=1,2,...,,又要满足 ∑ n i = N \sum n_i=N ni=N,所以可以知道上界就是根号级别 n i = 1 , 2 , . . . , N n_i=1,2,...,\sqrt N ni=1,2,...,N

#include <map>
#include <cstdio>
using namespace std; 
#define int long long 
#define mod 998244353
#define maxn 50005
map < int, int > color, cnt;
int fac[maxn], inv[maxn];
int n;

int qkpow( int x, int y ) {
	int ans = 1;
	while( y ) {
		if( y & 1 ) ans = ans * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return ans;
}

void init() {
	fac[0] = inv[0] = 1;
	for( int i = 1;i <= n;i ++ ) 
		fac[i] = fac[i - 1] * i % mod;
	inv[n] = qkpow( fac[n], mod - 2 );
	for( int i = n - 1;i;i -- ) 
		inv[i] = inv[i + 1] * ( i + 1 ) % mod;
}

int C( int n, int m ) {
	if( n < m ) return 0;
	else return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

signed main() {
	scanf( "%lld", &n );
	init();
	for( int i = 1, x;i <= n;i ++ ) {
		scanf( "%lld", &x );
		color[x] ++;//颜色x的出现次数 
	}
	for( auto it : color )	
		cnt[it.second] ++;//颜色出现次数为x的颜色个数
	for( int i = 1;i <= n;i ++ ) {
		int ans = 0;
		for( auto it : cnt ) 
			ans = ( ans + ( C( n, i ) - C( n - it.first, i ) + mod ) % mod * it.second ) % mod;
		printf( "%lld\n", ans * qkpow( C( n, i ), mod - 2 ) % mod );
	}
	return 0;
}

后言: H H H就是 F W T FWT FWTatcoder-abc很喜欢在最后考些鹅心算法模板,不想补了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值