Educational Codeforces Round 54 (Rated for Div. 2)A B C D

A. Minimizing the String

题意:问最多删去一个字符,如何变为字典序最小的串。
题解:明显是贪心了,从前往后删,找到第一个 s [ i ] > s [ i + 1 ] s[i] > s[i + 1] s[i]>s[i+1]的删去即可。找不到就删去最后一个字符。

#include<bits/stdc++.h>

using namespace std;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int n;
	string s;
	cin>>n>>s;
	string t = "";
	for(int i = 0; i < s.length(); ++i){
		if(i == 0 && s[0] > s[1]) {
			t = s.substr(1,s.length());
			break;
		}
		if(i == n - 1) {
			t = s.substr(0,s.length() - 1);
			break;
		}
		if(s[i] > s[i + 1]) {
			t = s.substr(0,i) + s.substr(i + 1,s.length());
			break;
		}
	}
	cout<< t <<endl;

    return 0;
}

代码

B. Divisor Subtraction

题意: n n n不断减去最小当前值的最小质因子,问最后变为 0 0 0至少需要多少次。
题解:

很容易发现如果是质数,只要减一次即可;
如果是偶数只需要减 n 2 \frac{n}{2} 2n次;
如果是奇数,就强行暴力减成偶数,再直接算出来即可。

代码

#include<bits/stdc++.h>

using namespace std;
const int N = 100100;
int prime[N];
bool vis[N];
int init()
{
	int k = 0;
	for(int i = 2; i < N; ++i) {
		if(vis[i] == 0) {
			prime[k++] = i;
		}
		for(int j = 2; j * i < N; ++j) {
			if(vis[i * j] == 0) {
				vis[i * j] = 1;
			}
		}
	}
	return k;
}
bool isPrime(long long n)
{
	for(int i = 2; 1LL * i * i <= n; ++i) {
		if(n % i == 0) return 0;
	}
	return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	long long n;
	int cnt = init();
	long long ans = 0;
	cin>>n;
	if(isPrime(n)) {
		cout<<1<<endl;
		return 0;
	}
	if(n % 2 == 0) {
		cout<<n / 2<<endl;
		return 0;
	}
		for(int i = 0; i < cnt; ++i) {
			while(n % prime[i] == 0) {
				if(n - prime[i] >= 0) 
				n -= prime[i];
				ans++; 
				if(n % 2 == 0) {
					ans += n / 2;
					n = 0;
					break;
				}
				//cout<<prime[i]<<endl;
				if(n == 0) break;
			}
			if(n == 0) break;
		}
	cout<< ans <<endl;
    return 0;
}

C. Meme Problem

题意:问满足 a + b = d , a ⋅ b = d a + b = d,a\cdot b = d a+b=d,ab=d a a a b b b
题解:首先容易发现明显是个二元一次方程,所以解一下就会发现 a , b a,b a,b的范围在 [ d − 2 , d ] [d-2,d] [d2,d],然后二分即可。

代码

#include<bits/stdc++.h>

using namespace std;
int d;
long double ans = 0;
bool love(long double x)
{
	if(x * ((long double)d - x) > d) {
		return 1;
	}
	return 0;
	
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int t;
	cin>>t;
	while(t--) {
		cin>>d;
		int f = 0;
		long double l = d - 2, r = d;
		if(d < 4) {
			if(d == 0) {
				printf("Y %.9f %.9f\n",0.0,0.0);
				continue;
			}else{
				printf("N\n");
				continue;
			}
		}
		if(d >= 4)
		while(l < r) {
			long double mid = (l + r) / 2, a = mid, b = d - mid;
			if(fabs(a * b - d) <= 1e-7) {
				ans = mid;
				break;
			}
			if(love(mid))
				l = mid;
			else
				r = mid;
		}
		if(ans){
			printf("Y %.9f %.9f\n",(double)ans,(double)(d-ans));
		}else{
			printf("N\n");
		}
	}
	
    return 0;
}

D. Edge Deletion

题意: n n n个点 m m m条边,最多保留 k k k条边,问最后在保证最短路径不变并且点尽可能多的情况下的图中剩余的路径编号。
题解:首先通过 d i j k s t r a dijkstra dijkstra跑一遍,得出来的最短路径一定是一棵树,所以为了点尽可能多只要保留最先找到的 k k k条边即可。

代码

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
#define Pii pair<LL,int>
#define P pair<LL,Pii>
const int N = 300100;
int n,m,k,from[N];

LL dis[N];
vector<int> ans;
vector<P> E[N];
void dijkstra(int s)
{
	memset(dis,0x3f3f,sizeof dis);
	dis[s] = 0;
	priority_queue<Pii, vector< Pii >, greater< Pii > > pq;
	pq.push({dis[s],s});
	int cnt = 0;
	while(cnt < k && !pq.empty()) {
		Pii cur = pq.top();
		pq.pop();
		LL d = cur.first;
		int u = cur.second;
		if(dis[u] < d) continue;
		if(u != 1) {
			cnt++;
			ans.push_back(from[u]);
		}
		for(P t : E[u]) {
			LL w = t.first;
			int f = t.second.second, v = t.second.first;
			if(dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				from[v] = f;
				pq.push({dis[v],v});
			}
		}
	}
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int x,y,w;
	cin>>n>>m>>k;
	for(int i = 1; i <= m; ++i) {
		cin>>x>>y>>w;
		E[x].push_back({w,{y,i}});
		E[y].push_back({w,{x,i}});
	}
	dijkstra(1);
	cout << ans.size() << endl;
	for(int iter : ans) {
		cout<< iter << ' ';
	}
	cout<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值