A:honoka和格点三角形
思路:由于三角形面积为2,而且保证三角形的一边与x轴或y轴平行,从而可以推出与某轴平行的边长度要么是1要么是2.
1.考虑满足题意的三角形中与x轴平行:

  • 与x轴平行的边长为2,对答案的贡献:m * (m - 2) % mod * (n - 1) % mod * 2 % mod;
  • 与x轴平行的边长为1,对答案的贡献:m * (m - 1) % mod * (n - 2) % mod * 2 % mod;

2.考虑满足题意的三角形中与y轴平行:

  • 与y轴平行的边长为2,对答案的贡献(舍弃与x轴平行的三角形,不重复计数):
    (n - 2) * (n - 2) % mod * (m - 1) % mod * 2 % mod;
  • 与y轴平行的边长为1,对答案的贡献(舍弃与x轴平行的三角形,不重复计数):
    (n - 2) * (n - 1) % mod * (m - 2) % mod * 2 % mod;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll m, n;
ll solve1(ll n, ll m){
    ll ans;
    ans = m * (m - 2) % mod * (n - 1) % mod * 2 % mod;
    return ans;
}
ll solve2(ll n, ll m){
    ll ans;
    ans = m * (m - 1) % mod * (n - 2) % mod * 2 % mod;
    return ans;
}
ll solve3(ll n, ll m){
    ll ans;
    ans = (n - 2) * (n - 2) % mod * (m - 1) % mod * 2 % mod;
    return ans;
}
ll solve4(ll n, ll m){
    ll ans;
    ans = (n - 2) * (n - 1) % mod * (m - 2) % mod * 2 % mod;
    return ans;
}
int main(){
    while(scanf("%lld%lld", &n, &m) != EOF){
        ll ans = 0;
        ans = solve1(n, m);
        ans = (ans + solve2(n, m)) % mod;
        ans = (ans + solve3(n, m)) % mod;
        ans = (ans + solve4(n, m)) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}

B:kotori和bangdream
思路:由于每一个音符都是等价的,直接利用数学公式求出一个音符的期望值

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll n, a, b, x;
int main(){
    while(scanf("%lld%lld%lld%lld", &n, &x, &a, &b) != EOF){
        ll up = a * x + b * (100 - x);
        up *= n;
        double ans = up / 100.0;
        printf("%.2f\n", ans);
    }
    return 0;
}

C:umi和弓道
思路:这道题把题目简化,每一个点都不在坐标轴上。所以我们就可以直接暴力弄,对于与umi在同一象限的,我们就直接忽略(因为你只能把板放在坐标轴上,所以肯定会把在同一象限的打掉)。不在同一象限的点,我们求出umi与它组成的线段与x轴或y轴的交点。与x轴的交点放在桶A,与y轴的交点放在桶B。然后按大小排序后,直接找枚举区间长度为n - k的答案,然后最后取min。具体细节,可以参考代码。
但是我这个代码,处理两个点表示的线段与x或y轴有无交点地方,写得很啰嗦。

处理交点,可以利用此方法
umi(x0, y0) A(x1, y1)
if(x0 * x1 < 0) x轴有交点
if(y0 * y1 < 0) y轴有交点

下面大篇幅代码,可以用上面思路简化。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll x, y;
int n, k;
vector<double>Y;
vector<double>X;
double Get_Y(ll x0, ll y0, ll x1, ll y1){
    if(x0 == x1) return y0 * 1.0;
    return (y1 * x0 - x1 * y0) / (1.0 * (x0 - x1));
}
double Get_X(ll x0, ll y0, ll x1, ll y1){
    //printf("x1 = %lld y1 = %lld\n", x1, y1);
    if(y0 == y1) return x0;
    return (x1 * y0 - x0 * y1) / (1.0 * (y0 - y1));
}
int check(ll x, ll y){
    if(x > 0 && y > 0) return 1;
    if(x > 0 && y < 0) return 4;
    if(x < 0 && y > 0) return 2;
    if(x < 0 && y < 0) return 3;
}
void print(){
    int Size = X.size();
    for(int i = 0; i < Size; i++){
        printf("X[%d] = %f\n", i + 1, X[i]);
    }
    Size = Y.size();
    for(int i = 0; i < Size; i++){
        printf("Y[%d] = %f\n", i + 1, Y[i]);
    }
}
int main(){
    while(scanf("%lld%lld%d%d", &x, &y, &n, &k) != EOF){
        Y.clear(); X.clear();
        int res = n - k;
        ll f, s;
        int opt = check(x, y);
        for(int i = 1; i <= n; i++){
            scanf("%lld%lld", &f, &s);
            int tmp = check(f, s);
            if(opt == tmp) continue;
            if(opt == 1){
                if(tmp == 2){
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                }
                else if(tmp == 3){
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else{
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
            }
            if(opt == 2){
                if(tmp == 1){
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                }
                else if(tmp == 3){
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else{
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
            }
            if(opt == 3){
                if(tmp == 1){
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else if(tmp == 2){
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else{
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                }
            }
            if(opt == 4){
                if(tmp == 1){
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else if(tmp == 2){
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                    double x1 = Get_X(x, y, f, s);
                    X.push_back(x1);
                }
                else{
                    double y1 = Get_Y(x, y, f, s);
                    Y.push_back(y1);
                }
            }
        }
        sort(X.begin(), X.end());
        sort(Y.begin(), Y.end());
        int Size = X.size();
        double ans = 1e15;
        for(int i = 0; i + res - 1 < Size; i++){
            int j = i + res - 1;
            ans = min(ans, X[j] - X[i]);
        }
        Size = Y.size();
        for(int i = 0; i + res - 1 < Size; i++){
            int j = i + res - 1;
            ans = min(ans, Y[j] - Y[i]);
        }
        //print();
        if(ans == 1e15) printf("-1\n");
        else printf("%.8f\n", ans);
    }
    return 0;
}

D:hanayo和米饭
思路:直接暴力枚举1-n谁没出现即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int n;
bool vis[maxn];
int main(){
    while(scanf("%d", &n) != EOF){
        int val;
        for(int i = 1; i < n; i++) scanf("%d", &val), vis[val] = true;
        for(int i = 1; i <= n; i++){
            if(!vis[i]) printf("%d\n", i);
        }
    }
    return 0;
}

E:rin和快速迭代
思路:f(x)表示x的因数个数 设x的质因数为,质因数对应的指数为,那么
感想:当时做这题的时候,我求质因数指数,算了一下大概复杂度是。可是,我在暴力跑1e12的时候,发现迭代次数好像挺小的,于是就暴力莽了一发,居然过了。但是数学证明我不太会,如果有会的,希望有人可以留言告诉我!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll n;
ll Get(ll n){
    ll ans = 1;
    for(ll i = 2; i * i <= n; i++){
        if(n % i == 0){
            int num = 1;
            while(n % i == 0){
                num++;
                n /= i;
            }
            ans *= num;
        }
    }
    if(n > 1) ans *= 2;
    return ans;
}
int main(){
    while(scanf("%lld", &n) != EOF){
        ll num = 0;
        while(n != 2){
            num++;
            n = Get(n);
        }
        printf("%lld\n", num);
    }
    return 0;
}

F:maki和tree
思路:理解统计方法后,我们发现黑点是特殊点,可以枚举。怎么枚举呢?
枚举其中一个黑点A,怎么统计这个点对答案的贡献呢?
我们把这棵树除黑点A的其余黑点从树中拿掉,这下就变成很多棵树。黑点A所在的那棵树就发现贡献计算公式,这个就显然求出贡献值。如果不懂,可以看代码。
所以可以用并查集维护白点集合的大小,方便统计答案

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll siz[maxn];
int fa[maxn];
int n;
char s[maxn];
vector<int>pos[maxn];
int find_fa(int x){
    if(x != fa[x]) return fa[x] = find_fa(fa[x]);
    return x;
}
void join(int x, int y){
    x = find_fa(x);
    y = find_fa(y);
    if(x == y) return ;
    fa[x] = y;
    siz[y] += siz[x];
}
int main(){
    while(scanf("%d", &n) != EOF){
        scanf("%s", s + 1);
        int x, y;
        for(int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1, pos[i].clear();
        for(int i = 1; i < n; i++){
            scanf("%d%d", &x, &y);
            if(s[x] == 'W' && s[y] == 'W'){
                join(x, y);
            }
            if(s[x] == 'W' && s[y] == 'B'){
                pos[y].push_back(x);
            }
            if(s[x] == 'B' && s[y] == 'W'){
                pos[x].push_back(y);
            }
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++){
            if(s[i] == 'B'){
                ll sum = 0, sum_1 = 0;
                int Size = pos[i].size();
                for(int j = 0; j < Size; j++){
                    sum += siz[find_fa(pos[i][j])];
                }
                ans += sum;
                for(int j = 0; j < Size; j++){
                    ll num = siz[find_fa(pos[i][j])];
                    sum_1 += num * (sum - num);
                }
                ans += sum_1 / 2;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

G:eli和字符串
思路:开26个桶记录位置,然后固定长度更新答案

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int n, k;
vector<int>pos[30];
char s[maxn];
int main(){
    while(scanf("%d%d", &n, &k) != EOF){
        scanf("%s", s + 1);
        for(int i = 1; i <= n; i++){
            int in = s[i] - 'a' + 1;
            pos[in].push_back(i);
        }
        int ans = maxn;
        for(int i = 1; i <= 26; i++){
            int Size = pos[i].size();
            if(Size < k) continue;
            for(int j = 0; j + k - 1 < Size; j++){
                int r = j + k - 1;
                ans = min(ans, pos[i][r] - pos[i][j] + 1);
            }
        }
        if(ans == maxn) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}

H:nozomi和字符串
思路:求最大值,发现具有二分性,所以利用左闭右开区间。
check函数如何写呢?
对于二分的一个答案len,以此固定长度枚举区间,判断是否把01区间转化为全0或全1,利用前缀和即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int pre[maxn];
char s[maxn];
int n, k;
bool check(int len){
    for(int i = 1; i + len - 1 <= n; i++){
        int j = i + len - 1;
        int sum = pre[j] - pre[i - 1];
        if(min(len - sum, sum) <= k) return true;
    }
    return false;
}
void print(){
    for(int i = 1; i <= n; i++){
        printf("pre[%d] = %d\n", i, pre[i]);
    }
}
int main(){
    while(scanf("%d%d", &n, &k) != EOF){
        scanf("%s", s + 1);
        for(int i = 1; i <= n; i++){
            int val = s[i] - '0';
            pre[i] = pre[i - 1] + val;
        }
        //print();
        int l, r;
        l = 1, r = n + 1;
        while(r - l > 1){
            int mid = (l + r) / 2;
            if(check(mid)){
                l = mid;
            }
            else{
                r = mid;
            }
        }
        printf("%d\n", l);
    }
    return 0;
}

I:nico和niconiconi
思路:简单dp,dp[i]表示从开头到第i个字符获得的最大分数
更新3种方式
dp[i] = max(dp[i], dp[i - 4] + a);
dp[i] = max(dp[i], dp[i - 6] + b);
dp[i] = max(dp[i], dp[i - 10] + c);

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll dp[maxn];
string s1 = "nico", s2 = "niconi", s3 = "niconiconi";
ll a, b, c, n;
char s[maxn];
bool check(int l, int r, int opt){
    if(l <= 0) return false;
    if(opt == 1){
        int Size = s1.size();
        for(int i = 0; i < Size; i++){
            if(s[i + l] != s1[i]) return false;
        }
    }
    if(opt == 2){
        int Size = s2.size();
        for(int i = 0; i < Size; i++){
            if(s[i + l] != s2[i]) return false;
        }
    }
    if(opt == 3){
        int Size = s3.size();
        for(int i = 0; i < Size; i++){
            if(s[i + l] != s3[i]) return false;
        }
    }
    return true;
}
int main(){
    while(scanf("%lld%lld%lld%lld", &n, &a, &b, &c) != EOF){
        scanf("%s", s + 1);
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++){
            dp[i] = dp[i - 1];
            if(check(i - 3, i, 1)){
                dp[i] = max(dp[i], dp[i - 4] + a);
            }
            if(check(i - 5, i, 2)){
                dp[i] = max(dp[i], dp[i - 6] + b);
            }
            if(check(i - 9, i, 3)){
                dp[i] = max(dp[i], dp[i - 10] + c);
            }
        }
        printf("%lld\n", dp[n]);
    }
    return 0;
}

J:u's的影响力
思路:乘法可以联想指数加法,然后写几个例子,发现指数呈现斐波拉契变化。
注意几个坑点:由于x,y,a很大,所以我们要先取模,防止利用快速幂时爆long long
利用欧拉降幂条件图片说明 1,所以坑点就是要判断a与p是否互质

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct mat{
    int r, c;
    ll a[5][5];
    mat(){
        memset(a, 0, sizeof(a));
    }
};
mat mul(mat A, mat B, ll mod){
    mat C;
    C.r = A.r; C.c = B.c;
    for(int i = 1; i <= C.r; i++){
        for(int j = 1; j <= C.c; j++){
            for(int k = 1; k <= A.c; k++){
                C.a[i][j] += A.a[i][k] * B.a[k][j] % mod;
                C.a[i][j] %= mod;
            }
        }
    }
    return C;
}
mat power(mat A, ll b, ll mod){
    mat res;
    res.c = res.r = A.r;
    for(int i = 1; i <= res.r; i++) res.a[i][i] = 1;
    while(b){
        if(b & 1) res = mul(res, A, mod);
        b >>= 1;
        A = mul(A, A, mod);
    }
    return res;
}
ll quick_mod(ll a, ll b, ll mod){
    ll sum = 1;
    while(b){
        if(b & 1) sum = sum * a % mod;
        a = a * a % mod;
        b /= 2;
    }
    return sum;
}
int main(){
    ll m = 1e9 + 7, ans = 1;
    ll n, x, y, a, b;
    cin >> n >> x >> y >> a >> b;
    if(n == 1) {cout << x % m << endl; return 0;}
    if(n == 2) {cout << y % m << endl; return 0;}
    if(x % m == 0 || y % m == 0 || a % m == 0) {cout << 0 << endl; return 0;}
    x %= m;
    y %= m;
    a = quick_mod(a % m, b, m); ///这里要注意a对m取模
    mat a_; a_.r = a_.c = 2; a_.a[1][1] = a_.a[1][2] = a_.a[2][1] = 1;
    mat opt1, opt2;
    opt1.r = opt2.r = 2; opt1.c = opt2.c = 1;
    opt1.a[1][1] = 0; opt1.a[2][1] = 1;
    opt2.a[1][1] = 1; opt2.a[2][1] = 0;
    a_ = power(a_, n - 2, m - 1);
    mat c = mul(a_, opt1, m - 1);
    //printf("x = %lld\n", c.a[1][1]);
    ans = ans * quick_mod(x, c.a[1][1], m) % m;
    c = mul(a_, opt2, m - 1);
    //printf("y = %lld\n", c.a[1][1]);
    ans = ans * quick_mod(y, c.a[1][1], m) % m;
    ///
    mat d; d.r = d.c = 3; d.a[1][1] = d.a[1][2] = d.a[1][3] = d.a[2][1] = d.a[3][3] = 1;
    mat opt3; opt3.r = 3; opt3.c = 1; opt3.a[1][1] = opt3.a[2][1] = 0; opt3.a[3][1] = 1;
    d = power(d, n - 2, m - 1);
    c = mul(d, opt3, m - 1);
    //printf("a = %lld\n", c.a[1][1]);
    ans = ans * quick_mod(a, c.a[1][1], m) % m;
    printf("%lld\n", ans);
    return 0;
}