题意就是题目意思,这里贪心的先把最大的字符选为第一个,接着是次大的。
然后这样会有个问题,子序列虽然不要求连续,但是要求按顺序,
所以可以设一个数组a[],a[i]表示i~n间最大的字符,这样就保证贪心不会出问题
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 2 * (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
char str[maxn];
char ans[maxn];
int maxp[maxn];
int main() {
while (~scanf("%s", str)) {
memset(maxp, 0, sizeof(maxp));
int len = strlen(str);
maxp[len - 1] = str[len - 1];
for (int i = len - 2; i >= 0; i--) {
int tmp = str[i];
maxp[i] = max(maxp[i + 1], tmp);
}
int cnt = 0;
memset(ans, 0, sizeof(ans));
for (int i = 0; i < len; i++) {
int tmp = str[i];
if (tmp == maxp[i]) {
ans[cnt++] = str[i];
}
}
printf("%s\n", ans);
}
return 0;
}
B 漂亮的树
给出一些树的高度,问最少修改多少颗树能使这n颗树形成屋顶状(等腰三角形,差值为1)
笔者读的时候脑子抽了想到去算需要修最少的长度了
要尽量少修的话,显然就是找出去掉阶梯性质之后的最多有多少颗树是等高的,也就是把这个形状拍扁。
因为数值有点多所以map哈希吧
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int a[maxn];
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
int m = (n + 1) / 2;
for (int i = 0; i < m; i++)
a[i] -= i;
for (int i = m; i < n; i++)
a[i] -= n - i - 1;
map<int, int>mp;
for (int i = 0; i < n; i++)
mp[a[i]]++;
int ans = 0;
for (map<int, int>::iterator it = mp.begin(); it != mp.end(); ++it)
ans = max(ans, it->second);
printf("%d\n", n - ans);
}
return 0;
}
对于一些点,如果他们能通过规则连在一起,把他们归到一个点集,
对于两个不能连在一起的点集,根据规则显然只需要再加一个点就能把这两个点集连起来
所以先把所有点归并集合然后算集合数-1就是答案
这里用并查集吧
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int pre[maxn];
struct nodes {
bool visx[1111], visy[1111];
}a[111];
void init(int n) {
for (int i = 0; i <= n; i++) {
pre[i] = i;
memset(a[i].visx, 0, sizeof(a[i].visx));
memset(a[i].visy, 0, sizeof(a[i].visy));
}
}
int find(int x) {
if (x == pre[x]) return x;
return pre[x] = find(pre[x]);
}
void unites(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
else if (x > y) pre[x] = y;
else pre[y] = x;
}
int main() {
int n;
while (~scanf("%d", &n)) {
int x, y;
init(n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &x, &y);
for (int j = 0; j < i; j++) {
if (a[j].visx[x] || a[j].visy[y])
unites(i, j);
}
a[i].visx[x] = a[i].visy[y] = 1;
}
int ans = 0;
for (int i = 0; i < n; i++)
if (i == find(i))
ans++;
printf("%d\n", ans - 1);
}
return 0;
}
待补
把或的结果丢到set里不断算就行了,因为set内的元素不重复所以实际运算量不会很大
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 4 * (int)(1e6) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
bool vis[maxn];
set<int> s[3];
int main(){
int n, cur = 0, x;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &x);
cur ^= 1;
s[cur].clear();
for (auto &it : s[cur ^ 1]) {
int tmp = x | it;
vis[tmp] = 1;
s[cur].insert(tmp);
}
vis[x] = 1;
s[cur].insert(x);
}
int ans = 0;
for (int i = 0; i < maxn; i++)
if (vis[i])
ans++;
printf("%d\n", ans);
return 0;
}
题目意思得 a[j]-a[i]<=d,转化过来就是a[i]>=a[j]-d
这样的话只要用二分查找到a[i],然后在i~j-1中选两个数就是符合题目的组合.
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 2 * (int)(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
LL a[maxn];
int main() {
int n;
LL d;
while (~scanf("%d%lld", &n, &d)) {
for (int i = 0; i < n; i++)
scanf("%lld", &a[i]);
LL ans = 0;
for (int i = n - 1; i >= 0; i--) {
int pos = lower_bound(a, a + n, a[i] - d) - a;
ans += LL(i - pos)*LL(i - pos - 1) / 2;
}
printf("%lld\n", ans);
}
return 0;
}