21. 小欧逛商店
小欧准备去商店买东西,商店中有n个物品从左向右摆成一排,第i个物品的体积为ai,价值为bi。小欧有一个容量为x的背包,她每次看到能装进背包里的物品都会装进去,如果装不进去就跳过这个物品。小欧想知道,她总共能买多少价值的物品?
思路:刚看到题以为是01背包,看到空间的限制是1e9还想了下优化。但是题目里面说只要能装进背包的就直接算入答案,于是直接遍历一次就好,若空间够放入当前物品就直接在答案上加上物品的价值。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
int n, x;
cin>>n>>x;
ll ans = 0;
for(int i=0; i<n; i++) {
int a, b;
cin>>a>>b;
if(a > x) continue;
x -= a;
ans += b;
}
cout<<ans<<endl;
return 0;
}
// 64 位输出请用 printf("%lld")
22. 小欧的字符串构造
小欧有一个字符串 s,她想构造一个长度为 k 的字符串 t,使得 s+t 或 t+s 拼成的字符串是回文串。
思路:首先比较需要构造的字符串的长度和原来字符串的长度。如果需要构造的字符串长度大于等于原字符串长度,只需要选择题目说的一种情况(注意是s+t 或 t+s)构造即可,此时一定有答案。如果需要构造的字符串长度小于原字符串的长度则需要看两种情况的时候原字符串s多出来的部分是否回文,若前面多出来的部分回文,则把t拼在s前面,反之则把t拼到s后面。
#include <bits/stdc++.h>
using namespace std;
string s;
bool check(int l, int r) {
// cout<<l<<" "<<r<<endl;
for(int i=l; i<=(l+r)/2; i++) if(s[i] != s[r-(i-l)]) return false;
return true;
}
int main() {
cin>>s;
int k;
cin >> k;
int n = s.size();
string ans;
if (k >= n) {
for(int i=0; i<k-n; i++) ans.push_back('a');
for(int i=n-1; i>=0; i--) ans.push_back(s[i]);
cout << ans << endl;
return 0;
}
bool b1 = check(0, n-k-1); // 连接到前面
bool b2 = check(k, n-1); // 连接到后面
if (!b1 && !b2) cout<<"-1"<<endl;
else if (b1) {
for(int i=0; i<k; i++) ans.push_back(s[n-i-1]);
cout<<ans<<endl;
}
else {
for(int i=k-1; i>=0; i--) ans.push_back(s[i]);
cout<<ans<<endl;
}
return 0;
}
// 64 位输出请用 printf("%lld")
23. 小欧皇
小欧正在扮演一个中世纪的皇帝。地图上有n个城市,其中有m条道路,每条道路连接了两个城市。小欧占领了其中一些城市。如果两个城市可以通过若干条道路互相到达,且这些道路经过的城市都是小欧占领的,那么这两个城市之间就可以通过经商获得收益1。请注意,每两个城市之间的收益只会被计算一次。现在,小欧准备占领一个未被占领的城市,使得总收益最大化。你能帮帮她吗?
思路:看到题目的时候可以联想到若要使一个或多个点集中的点两两互通,可能需要使用维护一个并查集。这里由于只需要多占领一个点,可以考虑当每次占领一个未被占领的点,对答案的贡献大小,由于可能不只一个联通块,需要在找到这个需要被占领的点后,再整体遍历一次,算上其他联通块的答案。
当一个联通块中有n个点的时候,对答案的贡献是:n * (n-1) / 2
#include<bits/stdc++.h>
#include <cstdio>
#include <queue>
#define ll long long
using namespace std;
vector<ll> G[100010], ans;
ll f[100010], siz[100010];
map<ll, ll> mp;
ll find(ll x) {
if(f[x] == x) return x;
else return f[x] = find(f[x]);
}
void merge(ll x, ll y) {
ll rt1 = find(x);
ll rt2 = find(y);
if(rt1 != rt2) {
f[rt1] = rt2;
siz[rt2] += siz[rt1];
}
}
int main()
{
ll n, m;
cin>>n>>m;
string s;
cin>>s;
for(ll i=0; i<m; i++) {
ll x,y;
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
for(ll i=1; i<=n; i++) {
siz[i] = 1;
f[i] = i;
}
for(ll i=1; i<=n; i++) {
if(s[i-1] == '0') continue;
for(ll j=0; j<G[i].size(); j++) {
if(s[G[i][j] - 1] == '0') continue;
merge(i, G[i][j]);
}
}
ll mx = 0;
for(ll i=1; i<=n; i++) {
if(s[i-1] == '1') continue;
ll len = 1;
ll sum = 0;
for(ll j=0; j<G[i].size(); j++) {
if(s[G[i][j] - 1] == '0') continue;
ll rt = find(G[i][j]);
if(mp[rt] == 1) continue;
len += siz[rt];
sum += siz[rt] * (siz[rt] - 1) / 2;
mp[rt] = 1;
}
mp.clear();
ll now = len*(len-1)/2 - sum;
if(now > mx) {
mx = now;
ans.clear();
ans.push_back(i);
}
else if(now == mx) ans.push_back(i);
}
sort(ans.begin(), ans.end());
for(int i=0; i<G[ans[0]].size(); i++) {
if(s[G[ans[0]][i] - 1] == '1') {
merge(ans[0], G[ans[0]][i]);
}
}
ll sum = 0;
for(int i=1; i<=n; i++) {
if(find(i) == i) sum += siz[i] * (siz[i] - 1) / 2;
}
cout << ans[0] << " " << sum << endl;
return 0;
}