门牌制作
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
int main() {
int cnt = 0;
rep(i, 1, 2020) {
int now = i;
while (now) {
if (now % 10 == 2) ++cnt;
now /= 10;
}
}
cout << cnt << '\n'; // 624
return 0;
} 既约分数
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
int main() {
int cnt = 0;
rep(i, 1, 2020) rep(j, 1, 2020) cnt += __gcd(i, j) == 1;
cout << cnt << '\n'; // 2481215
return 0;
} 蛇形填数
#include <bits/stdc++.h>
using namespace std;
void put(int x, int y, int val) {
if (x == 20 and y == 20) cout << val << endl, exit(0);
if (x == 1 and y % 2 == 1)
put(x, y + 1, ++val);
else if (y == 1 and x % 2 == 0)
put(x + 1, y, ++val);
else if ((x + y) % 2 == 1)
put(x + 1, y - 1, ++val);
else
put(x - 1, y + 1, ++val);
}
int main() {
put(1, 1, 1); // 761
return 0;
} 跑步锻炼
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
inline bool isLeapYear(int y) {
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
bool isDate(int n) {
int y = n / 10000;
int m = n / 100 % 100;
int d = n % 100;
if (m < 1 || m > 12) return 0;
if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
return d >= 1 && d <= 31;
else if (m == 2) {
if (isLeapYear(y))
return d >= 1 && d <= 29;
else
return d >= 1 && d <= 28;
} else
return d >= 1 && d <= 30;
}
int nextDate(int n) {
int y = n / 10000;
int m = n / 100 % 100;
int d = n % 100;
if (m == 12) {
if (d == 31)
y += 1, m = 1, d = 1;
else
d += 1;
} else if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10) {
if (d == 31)
m += 1, d = 1;
else
d += 1;
} else if (m == 2) {
if (isLeapYear(y)) {
if (d == 29)
m += 1, d = 1;
else
d += 1;
} else {
if (d == 28)
m += 1, d = 1;
else
d += 1;
}
} else {
if (d == 30)
m += 1, d = 1;
else
d += 1;
}
return y * 10000 + m * 100 + d;
}
int main() {
int cnt = 0, th = 5;
for (int i = 20000101; i <= 20201001; i = nextDate(i)) {
if (th + 1 == 1 || i % 100 == 1)
cnt += 2;
else
++cnt;
th = (th + 1) % 7;
}
cout << cnt << '\n'; // 8879
return 0;
} 七段码
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int fa[N];
void init() {
for (int i = 0; i < N; ++i) fa[i] = i;
}
int Find(int x) {
if (x != fa[x]) fa[x] = Find(fa[x]);
return fa[x];
}
bool isOn[N];
void merge(int x, int y) {
if (!isOn[x] || !isOn[y]) return;
fa[Find(y)] = Find(x);
}
bool isOk(int sta) {
init();
for (int i = 1; i <= 7; ++i) {
isOn[i] = sta & 1;
sta >>= 1;
}
merge(1, 2);
merge(1, 6);
merge(2, 3);
merge(2, 7);
merge(3, 7);
merge(3, 4);
merge(4, 5);
merge(5, 6);
merge(5, 7);
merge(6, 7);
int blocks = 0;
for (int i = 1; i <= 7; ++i)
if (isOn[i]) blocks += (i == Find(i));
return blocks == 1;
}
int main() {
int cnt = 0;
for (int i = 1; i < (1 << 7); ++i) cnt += isOk(i);
cout << cnt << '\n'; // 80
return 0;
} 成绩统计
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, x, ok = 0, good = 0;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> x;
if (x >= 60) ++ok;
if (x >= 85) ++good;
}
double r1 = ok * 100.0 / n;
double r2 = good * 100.0 / n;
printf("%.0lf%%\n%.0lf%%\n", r1, r2);
return 0;
} 回文日期
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
inline bool isLeapYear(int y) {
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
int nextDate(int n) {
int y = n / 10000;
int m = n / 100 % 100;
int d = n % 100;
if (m == 12) {
if (d == 31)
y += 1, m = 1, d = 1;
else
d += 1;
} else if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10) {
if (d == 31)
m += 1, d = 1;
else
d += 1;
} else if (m == 2) {
if (isLeapYear(y)) {
if (d == 29)
m += 1, d = 1;
else
d += 1;
} else {
if (d == 28)
m += 1, d = 1;
else
d += 1;
}
} else {
if (d == 30)
m += 1, d = 1;
else
d += 1;
}
return y * 10000 + m * 100 + d;
}
int digit[10];
bool isPalindrome(int n) {
for (int i = 1; i <= 8; ++i) {
digit[i] = n % 10;
n /= 10;
}
for (int L = 1, R = 8; L <= R; ++L, --R)
if (digit[L] != digit[R]) return 0;
return 1;
}
inline bool ABAB() {
return digit[1] != digit[2] && digit[1] == digit[3] && digit[2] == digit[4];
}
int main() {
int n;
cin >> n;
int x = nextDate(n);
int ans = 0;
while (1) {
if (isPalindrome(x)) {
if (!ans) ans = x;
if (ABAB()) break;
}
x = nextDate(x);
}
printf("%d\n%d\n", ans, x);
return 0;
} 子串分值和
将枚举区间算权值的问题转化为枚举点对总权值的贡献的问题,也就是枚举单点所能贡献的区间。
简单来说就是,将题面转化为:每个字符串内,只有第一次出现的字符才会对这个字符串产生贡献。那么枚举每个字符的贡献,处理一下它上次出现的位置即可。
#include <bits/stdc++.h>
#define ch str[i] - 'a'
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int last[30], n;
char str[N];
int main() {
scanf("%s", str + 1);
n = strlen(str + 1);
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans += 1ll * (i - last[ch]) * (n - i + 1);
last[ch] = i;
}
printf("%lld\n", ans);
return 0;
} 一道很类似的题目:http://lx.lanqiao.cn/problem.page?gpid=T792
唯一的不同在于,权值的定义是只出现了一次的字符。那么处理一下其后第一次出现的字符位置即可。
#include <bits/stdc++.h>
#define pr(x) printf("%lld\n", (x))
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
char s[N];
#define ch s[i] - 'a'
int last[30];
int nxt[N];
int main() {
scanf("%s", s + 1);
int n = strlen(s + 1);
for (int i = 1; i <= n; ++i) {
if (last[ch]) nxt[last[ch]] = i;
last[ch] = i;
}
memset(last, 0, sizeof last);
ll ans = 0;
for (int i = 1; i <= n; ++i) {
if (!nxt[i]) nxt[i] = n + 1;
ans += 1LL * (i - last[ch]) * (nxt[i] - i);
last[ch] = i;
}
pr(ans);
return 0;
} 平面切分
给出n条直线,
计算这些直线将平面分成了几个部分
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
set<pii> st;
pii a[1005];
int main() {
int n;
cin >> n;
pii t;
int p = 0;
for (int i = 1; i <= n; ++i) { // 去重
cin >> t.first >> t.second;
if (!st.count(t)) {
a[++p] = t;
st.insert(t);
}
}
int ans = 1; // 初始就是一个平面
pair<long double, long double> u;
set<pair<long double, long double> > points;
for (int i = 1; i <= p; ++i) {
for (int j = i + 1; j <= p; ++j) {
if (a[i].first == a[j].first) continue;
u.first = 1.0L * (a[j].second - a[i].second) /
(a[i].first - a[j].first); //交点的x坐标
u.second = a[i].first * u.first + a[i].second; //交点的y坐标
points.insert(u);
}
ans += points.size() + 1;
// 其他直线 将 i直线 切割为 线上的交点数量+1部分
points.clear();
}
cout << ans << '\n';
return 0;
} 字串排序
30分可以直接暴力出
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int countBubbleSort(string s) {
int res = 0;
bool f = 0;
do {
f = 0;
for(int i = 1, sz = s.length(); i < sz; ++i) {
if(s[i] < s[i - 1]) {
swap(s[i], s[i - 1]);
++res;
if(!f) f = 1;
}
}
} while (f);
return res;
}
string ans[25];
bool fin = 0;
inline int getSum(int n) {
return (1 + n) * (n) / 2;
}
bool isFin(int n) {
int low = getSum(n - 1);
int up = getSum(n);
for(int i = low ; i <= up; ++i) {
if(ans[i] == "")return 0;
}
return 1;
}
void dfs(string s, int len) {
if(fin)return;
if(len == 0) {
int cnt = countBubbleSort(s);
if(ans[cnt] == "") {
ans[cnt] = s;
if(isFin(s.size()))fin = 1;
}
return;
};
for(char c = 'a'; c <= 'e'; ++c)dfs(s + c, len - 1);
}
int main() {
for(int i = 2; i <= 7; ++i) {
fin = 0;
dfs("", i);
}
for(int i = 1; i <= 20; ++i)cout << ans[i] << '\n';
return 0;
} #include<bits/stdc++.h>
using namespace std;
string ans[10020] = {"a","ba", "baa", "cba", "bbaa", "cbaa", "dcba", "bcbaa", "cbbaa", "dcbaa", "edcba", "bdcbaa", "ccbbaa", "dcbbaa", "edcbaa", "fedcba", "bedcbaa", "cdcbbaa", "dccbbaa", "edcbbaa", "fedcbaa"};
int main() {
int n;
cin >> n;
cout << ans[n];
return 0;
} 仔细考虑发现
- 答案字符串一定是非升序的,否则会浪费,即不是最优,那么lead字符一定是最大的,而严格降序必定是该长度的最后一个,位置满足公差为1的等差数列。
- 所以串长
,其覆盖范围为
根据第一点,即可优化暴力(剪枝)到覆盖到长度13的串,也许能40分
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
int countBubbleSort(string s) {
int res = 0;
bool f = 0;
do {
f = 0;
for (int i = 1, sz = s.length(); i < sz; ++i) {
if (s[i] < s[i - 1]) {
swap(s[i], s[i - 1]);
++res;
if (!f) f = 1;
}
}
} while (f);
return res;
}
string ans[125];
bool fin = 0;
inline int getSum(int n) { return (1 + n) * (n) / 2; }
bool isFin(int n) {
int low = getSum(n - 1);
int up = getSum(n);
for (int i = low; i <= up; ++i) {
if (ans[i] == "") return 0;
}
return 1;
}
void dfs(string s, int len) {
if (fin) return;
if (len == 0) {
int cnt = countBubbleSort(s);
if (ans[cnt] == "") {
ans[cnt] = s;
if (isFin(s.size())) fin = 1;
}
return;
};
if (s == "")
for (char c = 'a'; c <= 'a' + len; ++c) dfs(s + c, len - 1);
else
for (char c = 'a'; c <= s.back(); ++c) dfs(s + c, len - 1);
}
int main() {
for (int i = 2; i <= 13; ++i) {
fin = 0;
dfs("", i);
}
// for (int i = 50; i <= 100; ++i) cout << ans[i] << '\n';
return 0;
} a ba baa cba bbaa cbaa dcba cbaaa cbbaa dcbaa edcba cbbaaa ccbbaa dcbbaa edcbaa fedcba ccbbaaa dcbbaaa dccbbaa edcbbaa fedcbaa
本题暂时搁置一下,记录一下100%的思路:
- 完全降序的序列能最大限度利用串长,所以它是同一串长下,所能表达的最大逆序数。由此,我们可以确定每一个长度,所覆盖的范围。
- 而如果26个字母都用完了以后,怎么办呢?我们不妨修改题面,限制只能用ABC三个字母,那么在此情况下暴搜,可以知道,尽可能均匀分布,剩下的指标,从后往前加就可以了:ccbbaaa
- 现在我们确定了串长,接下来从前往后逐位尝试替换即可,测试当前是否达到该逆序数即可。此处可以通过一个前缀和的操作使复杂度降到

京公网安备 11010502036488号