C. Polycarp Restores Permutation
题意:给你序列相邻两项的差值,现在要求你恢复这个序列。
题解:我们给差值序列
q
i
q_i
qi做前缀和,明显
q
i
q_i
qi最小的位置就是
1
1
1的位置,因此我们就可以通过
1
1
1的位置来推出其它位置。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
typedef long long LL;
using namespace std;
const int N = 2E5+10;
int a[N],q[N],vis[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n, f = 1, idx = 0;
LL MIN = 0;
cin >> n;
for(int i = 1; i <= n - 1; ++i) {
cin >> q[i];
}
LL sum = 0;
for(int i = 1; i < n; ++i) {
sum += q[i];
if(MIN > sum) {
MIN = sum;
idx = i;
}
}
a[idx] = 1;
for(int i = idx - 1; i >= 0; --i) {
a[i] = a[i + 1] - q[i + 1];
}
for(int i = idx + 1; i < n; ++i) {
a[i] = a[i - 1] + q[i];
}
for(int i = 0; i < n; ++i) {
if(a[i] >= 1 && a[i] <= n)
vis[a[i]]++;
}
for(int i = 1; i <= n; ++i) if(vis[i] != 1) return cout << -1 << endl,0;
for(int i = 0; i < n; ++i) {
cout << a[i] << ' ';
}
return 0;
}
D. Colored Boots
题意:给出两个字符串,要求最大相等字符配对,其中字符
?
?
?可以和任何一个字符配对。
题解:贪心。先让相同的配对,然后让左面字符串中的字符
?
?
?和右面不是
?
?
?的字符配对,再让右面字符串中的字符
?
?
?和左面不是
?
?
?的字符配对,最后让左面的
?
?
?和右面的
?
?
?配对。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
const int N = 150010;
vector<int> L[250],R[250],dL,dR;
string a,b;
vector<pair<int,int>> ans;
bool vis_L[N],vis_R[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n;
cin >> n >> a >> b;
for(int i = 0; i < n; ++i) {
L[a[i]].push_back(i + 1);
R[b[i]].push_back(i + 1);
}
for(int i = 0; i < 250; ++i) {
if(i == (int)'?') continue;
int k = min(L[i].size(), R[i].size());
for(int j = 0; j < k; ++j) {
ans.push_back(make_pair(L[i][j],R[i][j]));
vis_L[L[i][j]] = vis_R[R[i][j]] = 1;
}
}
for(int i = 1; i <= n; ++i) {
if(vis_R[i] == 0 && b[i] != '?') {
dR.push_back(i);
}
}
for(int i = 0; i < L[(int)'?'].size() && i < dR.size(); ++i) {
if(vis_L[L[(int)'?'][i]] == 0 && vis_R[dR[i]] == 0) {
ans.push_back(make_pair(L[(int)'?'][i],dR[i]));
vis_L[L[(int)'?'][i]] = vis_R[dR[i]] = 1;
}
}
for(int i = 1; i <= n; ++i) {
if(vis_L[i] == 0 && a[i] != '?') {
dL.push_back(i);
}
}
for(int i = 0; i < R[(int)'?'].size() && i < dL.size(); ++i) {
if(vis_R[R[(int)'?'][i]] == 0 && vis_L[dL[i]] == 0) {
ans.push_back(make_pair(dL[i],R[(int)'?'][i]));
vis_R[R[(int)'?'][i]] = vis_L[dL[i]] = 1;
}
}
int p = 0, q = 0;
dL.clear();
dR.clear();
for(int i = 0; i < L[(int)'?'].size(); ++i) {
if(vis_L[L[(int)'?'][i]] == 0) {
p++;
dL.push_back(L[(int)'?'][i]);
}
}
for(int i = 0; i < R[(int)'?'].size(); ++i) {
if(vis_R[R[(int)'?'][i]] == 0) {
q++;
dR.push_back(R[(int)'?'][i]);
}
}
int mm = min(dL.size(), dR.size());
for(int i = 0; i < mm; ++i) {
ans.push_back(make_pair(dL[i],dR[i]));
}
cout << ans.size() << endl;
for(int i = 0; i < ans.size(); ++i) {
cout << ans[i].first << ' ' << ans[i].second << endl;
}
return 0;
}
E. Superhero Battle
题意:怪物生命值为
H
H
H,每一轮有
n
n
n分钟,在这一轮中的第
i
i
i分钟,怪物的血量会变为
h
=
h
+
d
i
h = h + d_i
h=h+di,问怪物死亡是第几分钟,如果打不死输出
−
1
-1
−1。
题解:我的做法复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),即二分搜索。首先做一个前缀和,二分搜索打怪轮数,然后去枚举在这一轮第几分钟可以把怪打死。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
typedef long long LL;
using namespace std;
const int N = 2E5+10;
LL sum[N],d[N],n,H;
bool ok(LL x,LL & ans)
{
x--;
ans = n + 1;
LL res = H + x * sum[n];
for(int i = 1; i <= n; ++i) {
if(res + sum[i] <= 0) {
ans = i;
return 1;
}
}
return res <= 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
cin >> H >> n;
for(int i = 1; i <= n; ++i) {
cin >> d[i];
sum[i] = sum[i - 1] + d[i];
}
LL l = 1, r = 1;
if(sum[n] != 0) {
r = max(r, -H / sum[n] + 1);
}
LL ans = -1, dx = n;
while(l <= r) {
LL mid = l + r >> 1;
if(ok(mid, dx)) {
ans = (mid - 1) * n + dx;
r = mid - 1;
}else{
l = mid + 1;
}
}
cout << ans << endl;
return 0;
}
F2. Same Sum Blocks (Hard)
题意:问区间和为
k
k
k时,最大的不相交区间个数。
题解:首先预处理出所有的区间和所对应的区间,然后对于每个可能的区间和的区间端点按右端点排序,贪心找出最大的区间不相交个数即可。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
const int N = 1501;
map<int,vector<pair<int,int>>> sum;
int a[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n;
cin >> n;
for(int i = 0; i < n; ++i) {
cin >> a[i];
}
for(int i = 0; i < n; ++i) {
int ret = 0;
for(int j = i; j < n; ++j) {
ret += a[j];
sum[ret].push_back(make_pair(j + 1,i + 1));
}
}
vector<pair<int,int>> ans;
for(auto it : sum) {
sort(it.second.begin(),it.second.end());
it.second.erase(unique(it.second.begin(),it.second.end()),it.second.end());
int r = 0;
vector<pair<int,int>> ret;
for(auto i : it.second) {
if(i.second > r) {
r = i.first;
ret.push_back(i);
}
}
if(ret.size() > ans.size()) {
ans = ret;
}
}
cout << ans.size() << endl;
for(auto i : ans) {
cout << i.second << ' ' << i.first << endl;
}
return 0;
}
G. Privatization of Roads in Treeland
题意:给一颗树染色,对于一个顶点,要求它的所有边颜色不能相同,否则这就是一个不合法点。题目最多允许
k
k
k个不合法点存在,问最少需要几种颜色可以将树染色。
题解:既然我们想要尽可能的少用颜色种类,那么我们就尽可能的将度数大的顶点当做不合法点,然后将剩下的
n
−
k
n-k
n−k个顶点作为合法点去给边染色即可。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define P pair<int,int>
using namespace std;
const int N = static_cast<const int>(2E5 + 10);
vector<P> E[N];
map<int,int> deg;
vector<P> vc;
int n,k,MAX,col[N];
void dfs(int u,int fa,int color)
{
for(const auto &i : E[u]) {
int v = i.first, idx = i.second;
if(v == fa) continue;
col[idx] = color;
dfs(v, u, (color + 1) % MAX);
color = (color + 1) % MAX;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int u,v;
cin >> n >> k;
for(int i = 0; i < n - 1; ++i) {
cin >> u >> v;
E[u].emplace_back(P(v,i));
E[v].emplace_back(P(u,i));
deg[u]++, deg[v]++;
}
for(const auto &i : deg) vc.emplace_back(i);
sort(vc.begin(), vc.end(), [](const pair<int,int> &x, const pair<int,int> &y) ->int {
return x.second > y.second;
});
MAX = vc[k].second;
dfs(vc[k].first,0, 0);
cout << MAX << endl;
for(int i = 0; i < n - 1; ++i) {
cout << col[i] + 1 << ' ';
}
return 0;
}