AtCoder Beginner Contest 235(A,B,C,D,E,F)

A. Rotate

签到题。
res = (a+b+c)*111

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

int main(){
	
	char a,b,c;
	cin >> a >> b >> c;
	int A = a - '0';
	int B = b - '0';
	int C = c - '0';
	int res = A * 111 + B * 111 + C * 111;
	
	cout << res << endl; 
			
	return 0;
}

B. Climbing Takahashi

模拟题。
每次都到更高的平台,第一次不能到达时break

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

int main(){
	
	int n;
	cin >> n;
	int res = 0, h;
	for(int i = 1; i <= n; i++){
		cin >> h;
		if(h > res) res = h;
		else break;
	}
			
	cout << res << endl;
		
	return 0;
}

C. The Kth Time Query

STL的用法。
每次询问 x 第 k 次出现时的位置,如果不存在输出 -1。
用 map 给所有数标号(离散化),用vector动态存储即可。

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

const int maxn = 1e6 + 5;
const ll mod = 1e9 + 7;

int a[maxn];
map<int, int> ID; int cnt = 0;
vector<int> v[maxn];

int main(){
	
	int n, q;
	cin >> n >> q;
	for(int i = 1; i <= n; i++) cin >> a[i];
	
	for(int i = 1; i <= n; i++){
		if(ID[a[i]] == 0){ // 第一次出现
			ID[a[i]] = ++cnt; // 标号
			v[cnt].push_back(i);
		}
		else v[ID[a[i]]].push_back(i); // 出现过
	}
	
	while(q--){
		int x, k;
		cin >> x >> k;
		if(v[ID[x]].size() >= k) cout << v[ID[x]][k-1] << endl;
		else cout << "-1" << endl;
	}
		
	return 0;
}

D. Multiply and Rotate

BFS裸题。注意数值范围即可。

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

const int maxn = 1e6 + 5;
const ll mod = 1e9 + 7;

int v[maxn];
queue<ll> qu;

int f(int x){
	if(x < 10 || x % 10 == 0) return 1e8;
	int y = x / 10;
	int len = log10(x);
	x = x % 10;
	int num = y + x * pow(10, len);
	return num;
}

int main(){
	
	memset(v, -1, sizeof(v));
	
	ll a, N;
	cin >> a >> N;
	
	v[1] = 0;
	qu.push(1);
	while(!qu.empty()){
		ll now = qu.front(); qu.pop();
		if(now == N) break; // 注意第一次搜到就 break
		if(now * a < 1e6 && v[now * a] == -1){ // 没被搜到,并且超过最大范围
			v[now * a] = v[now] + 1;
			qu.push(now * a);
		}
		int tmp = f(now);
		if(tmp < 1e6 && v[tmp] == -1){ // 没被搜到,并且超过最大范围
			v[tmp] = v[now] + 1;
			qu.push(tmp);
		}
	}
	
	cout << v[N] << endl;
				
	return 0;
}

E. MST + 1

有一个无向连通图 M,每次询问给出一条边 e,询问 e 加入到 M 中是否会影响 M 的最小生成树。
把 M 中的边和查询边放到一起跑最小生成树算法,但是注意查询边只判断不改变连通性

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

const int maxn = 1e6 + 5;
const ll mod = 1e9 + 7;

typedef struct Node{
	int u;
	int v;
	int w;
	int id;
} node;

node a[maxn];

bool cmp(node A, node B){
	if(A.w == B.w) return A.id > B.id;
	return A.w < B.w;
}

int f[maxn], ans[maxn];
int find(int x){
	if(x == f[x]) return x;
	else return f[x] = find(f[x]);
}

void join(int x, int y){
	int fx = find(x);
	int fy = find(y);
	if(fx != fy) f[fx] = fy;
}

int main(){
	
	int n, m, q;
	cin >> n >> m >> q;
	int u, v, w;
	for(int i = 1; i <= m; i++){
		cin >> u >> v >> w;
		a[i] = {u, v, w, 0};
	}
	for(int i = 1; i <= q; i++){
		cin >> u >> v >> w;
		a[m+i] = {u, v, w, i};
	}	
	
	sort(a+1, a+1+m+q, cmp); // 按权值排序,注意权值相同时优先查询边
	for(int i = 1; i <= n; i++) f[i] = i;
	for(int i = 1; i <= m+q; i++){
		if(a[i].id == 0) join(a[i].u, a[i].v); // 原图的中的边
		else{  // 查询边只判断不加入
			u = find(a[i].u);
			v = find(a[i].v);
			if(u != v) ans[a[i].id] = 1;
		}
	}
	
	for(int i = 1; i <= q; i++){
		if(ans[i]) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
				
	return 0;
}

F. Variety of Digits

数位dp + 状压dp。

询问 1 1 1 n n n 中,数位包含 c 1 , . . . , c m c_1,...,c_m c1...cm 的数的和。

思路
考虑如何表示数位包含 c 1 , . . . , c m c_1,...,c_m c1...cm 的数。二进制,如用 1011 0 2 10110_2 101102 来表示包含数位 2,3 和 5 的数。
n e e d = ( 1 < < c 1 ) + ( 1 < < c 2 ) + . . . + ( 1 < < c m ) need = (1<<c_1) + (1<<c_2) + ... + (1<<c_m) need=(1<<c1)+(1<<c2)+...+(1<<cm) r e s = ∑ 0 1024 s u m i [ i & n e e d = = n e e d ] res =\sum_{0}^{1024}sum_{i} [ i \& need == need] res=01024sumi[i&need==need]
如何数位dp,对于 201653 201653 201653

  • 当前缀等于 201 201 201 时,第四位的取值范围是 0 0 0 6 6 6
  • 当前缀小于 201 201 201 时,第四位的取值范围时 0 0 0 9 9 9

所以,设

  • d p i , 0 dp_{i,0} dpi,0 表示前缀等于 X X X 时状态为 i i i 的数的个数, s u m i , 0 sum_{i,0} sumi,0 表示前缀等于 X X X 时状态为 i i i 的数的和
  • d p i , 1 dp_{i,1} dpi,1 表示前缀小于 X X X 时状态为 i i i 的数的个数, s u m i , 1 sum_{i,1} sumi,1 表示前缀小于 X X X 时状态为 i i i 的数的和

状态转义参见代码。

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

const ll mod = 998244353;

int main(){
	string s;
	cin >> s;
	int n;
	cin >> n;
	int need = 0, x;
	for(int i = 1; i <= n; i++) cin >> x, need |= (1<<x);
	
	vector<vector<ll> > dp(1024, vector<ll>(2));
	vector<vector<ll> > sm(1024, vector<ll>(2));
	dp[0][0] = 1;	// 初始都不选的时候为0
	
	for(auto c : s){
		vector<vector<ll> > ndp(1024, vector<ll>(2));
		vector<vector<ll> > nsm(1024, vector<ll>(2));
		for(int i = 0; i < 1024; i++){
			for(int d = 0; d < 10; d++){
				int j = i | (1<<d); 
				if(i == 0 && d == 0) j = i; // 特殊情况
				if(d < c-'0'){ // 前缀相等,d小于当前位,得到小于当前位的数
					ndp[j][1] += dp[i][0]; // 计数
					nsm[j][1] += sm[i][0] * 10 + d * dp[i][0]; // 多了一位一位,之前的值 * 10 + 当前数的影响
					ndp[j][1] %= mod; nsm[j][0] %= mod;
				}
				if(d == c-'0'){ // 前缀相等,d等于当前位,得到等于当前位的数
					ndp[j][0] += dp[i][0];
					nsm[j][0] += sm[i][0] * 10 + d * dp[i][0];
					ndp[j][0] %= mod; nsm[j][0] %= mod;
				}
				// 前缀小于,当前位取0~9,得到小于当前的数
				ndp[j][1] += dp[i][1];
				nsm[j][1] += sm[i][1] * 10 + d * dp[i][1];
				ndp[j][1] %= mod; nsm[j][1] %= mod;
			}
		}
		swap(dp, ndp);
		swap(sm, nsm);
	}
	
	ll res = 0;
	for(int i = 0; i < 1024; i++) if((i & need) == need) res = (res + sm[i][0] + sm[i][1]) % mod;
	cout << res << endl;
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值