Codeforces Round #547 (Div. 3) C D E F G

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 nk个顶点作为合法点去给边染色即可。

代码

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值