门牌制作

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

仔细考虑发现

  1. 答案字符串一定是非升序的,否则会浪费,即不是最优,那么lead字符一定是最大的,而严格降序必定是该长度的最后一个,位置满足公差为1的等差数列。
  2. 所以串长,其覆盖范围为

根据第一点,即可优化暴力(剪枝)到覆盖到长度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%的思路:

  1. 完全降序的序列能最大限度利用串长,所以它是同一串长下,所能表达的最大逆序数。由此,我们可以确定每一个长度,所覆盖的范围。
  2. 而如果26个字母都用完了以后,怎么办呢?我们不妨修改题面,限制只能用ABC三个字母,那么在此情况下暴搜,可以知道,尽可能均匀分布,剩下的指标,从后往前加就可以了:ccbbaaa
  3. 现在我们确定了串长,接下来从前往后逐位尝试替换即可,测试当前是否达到该逆序数即可。此处可以通过一个前缀和的操作使复杂度降到