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,a⋅b=d的
a
a
a和
b
b
b。
题解:首先容易发现明显是个二元一次方程,所以解一下就会发现
a
,
b
a,b
a,b的范围在
[
d
−
2
,
d
]
[d-2,d]
[d−2,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;
}