[HG]奋斗赛B

T1

>传送门<

记忆化搜索,听说有更简单的方法(但博主比较菜)

#include <cstdio>
#include <cstdlib>
#define ll long long

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

int a[105], n;
int vis[105];

void DFS(int pos, int floor){
    if (vis[pos])
        return ;
    vis[pos] = 1;
    for (int i = ((n - pos) & 1) ? (n - 1) : n; i >= pos; i -= 2){
        if (i == n){
            if (a[i] & 1){
                if (floor & 1){
                    printf("Yes");
                    exit(0);
                }
            }
        }
        else{
            if ((a[i] & 1) && (a[i + 1] & 1)){
                if (i + 1 == n){
                    if (!(floor & 1)){
                        printf("Yes");
                        exit(0);
                    }
                }
                DFS(i + 1, floor + 1);
            }
        }
    }
}

int main(){
    n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    if (!(a[1] & 1) || !(a[n] & 1)){
        printf("No");
        return 0;
    }
    DFS(1, 1);
    printf("No");
    return 0;
}

T2

>传送门<

第1个点肯定要选的,暴力枚举第一条线段的第二个点在哪里,然后暴力模拟,注意第二个点可能为空

#include <cstdio>
#include <cmath>
#define ll long long

const double DEL = 1e-14;

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

double myAbs(double a){
    return (a > 0) ? a : -a;
}

double equal(double a, double b){
    if (myAbs(a - b) <= DEL)
        return 1;
    else
        return 0;
}

double y[1005];

int main(){
    int n = read();
    if (n <= 2){
        printf("Yes
");
        return 0;
    }
    for (int i = 0; i < n; ++i)
        y[i] = read();
    double lineA, lineB;
    int b1 = -1, b2 = -1;
    for (int i = 1; i < n; ++i){
        lineA = (y[i] - y[0]) / (double)(i);
        b1 = b2 = -1;
        int j;
        for (j = 1; j < n; ++j){
            if (j == i)
                continue;
            if (!equal((y[j] - y[0]) / (double)(j), lineA)){
                if (b1 == -1){
                    b1 = j;
                }else if (b2 == -1){
                    b2 = j;
                    lineB = (y[b2] - y[b1]) / (double)(b2 - b1);
                    if (!equal(lineA, lineB))
                        break;
                }else{
                    if (!equal((y[j] - y[b1]) / (double)(j - b1), lineB))
                        break;
                }
            }
        }
        if (j == n){
            if (b1 != -1){
                printf("Yes
");
                return 0;
            }
        }
    }
    double line1 = y[2] - y[1];
    int i;
    for (i = 3; i < n; ++i){
        if (!equal((y[i] - y[1]) / (double)(i - 1), line1))
            break;
    }
    if (i == n && (!equal((y[1] - y[0]), line1)))
        printf("Yes
");
    else
        printf("No
");
    return 0;
}

T3

>传送门<

发现不管怎么合并,结果都一样,于是等差数列求和公式用一用AC

#include <cstdio>
#define ll long long

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

ll getNum(ll a){
    return (((1 + a) * a) >> 1);
}

int main(){
    int k = read();
    if (k == 0){
        printf("ab");
        return 0;
    }
    char ch = 'a';
    while (k > 0){
        int l = 0, r = 100000, mid, ans = 0;
        while (l <= r){
            mid = (l + r) >> 1;
            if (getNum(mid) > k){
                r = mid - 1;
            }else{
                l = mid + 1;
                ans = mid;
            }
        }
        k -= getNum(ans);
        for (int i = 0; i <= ans; ++i)
            printf("%c", ch);
        ++ch;
    }
    return 0;
}

T4

>传送门<

欧拉筛,二分AC

#include <cstdio>
#include <map>
#include <cmath>
#include <algorithm>
#define ll long long

using namespace std;

int a[10000005], qzh[1000005];

int primes[10000005];
int prime_num = 1;
bool is_not_primes[10000005] = {false};

map<int, int> mp;

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

void getPrime(int n){
    is_not_primes[0] = true;
    is_not_primes[1] = true;
    for (int i = 2; i <= n; i++){
        if (is_not_primes[i] == false)
            primes[prime_num++] = i;
        for (int j = 1; (j < prime_num) && (primes[j] * i <= n); j++){
            is_not_primes[primes[j] * i] = true;
            if ((i % primes[j]) == 0)
                break;
        }
    }
}

int main(){
    getPrime(10000000);
    int n = read();
    for(int i = 1; i <= n; ++i){
        int x = read();
        ++a[x];
    }
    for(int i = 1; i < prime_num; ++i)
        for(int j = primes[i]; j <= 10000000; j += primes[i])
            qzh[i] += a[j];
    for(int i = 1; i < prime_num; ++i)
            qzh[i] += qzh[i - 1];
    int m = read(), l, r;
    for(int i = 1; i <= m; ++i){
        l = read(), r = read();
        ll ans_r = qzh[lower_bound(primes + 1, primes + prime_num, r + 1) - primes - 1];
        ll ans_l = qzh[lower_bound(primes + 1, primes + prime_num, l) - primes - 1];
        printf("%lld
", ans_r - ans_l);
    }
}

T5

>传送门<

真正难的题目(目测实测洛谷黑题),因为我比较菜,不会分块cdq分治,差分乱搞的算法,只能打一发树套树,

如何使用树套树呢?

  我们把一维问题转换成二维问题,一个点的横坐标就是这个点的位置,纵坐标是这个点前一个与它颜色相同的点的位置,权值是横坐标减纵坐标。
  这里查询[l,r]区间的答案,就是二维平面上(l,l)点和(r,r)点组成的矩阵内的权值之和。

  原理?占坑代填

然后预处理再上树套树板子就行了

#include <cstdio> 
#include <vector>
#include <set>
#define ll long long

using namespace std;

ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

//SegmentTree
long long s[12000000];
int lc[12000000], rc[12000000];
int node_cnt = 0;
void Add(int &pos, int l, int r, int k, ll val){
    if (!pos)
        pos = ++node_cnt;
    s[pos] += val; 
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    if (k <= mid)
        Add(lc[pos], l, mid, k, val);
    else
        Add(rc[pos], mid + 1, r, k, val);
}
long long Query(int pos, int l, int r, int k){
    if (!pos)
        return 0;
    if (l == r)
        return s[pos];
    int mid = (l + r) >> 1;
    if (k <= mid)
        return Query(lc[pos], l, mid, k) + s[rc[pos]];
    else
        return Query(rc[pos], mid + 1, r, k);
}

int rt[100005], fst[100005];

//fentree
struct fenTree{
    #define lowbit(x) (x & -x)
    void add(int k, int pos, ll val, int n){
        for (int i = k; i <= n; i += lowbit(i))
            Add(rt[i], 1, n, pos, val);
    }
    ll qry(int k, int pos, int n) {
        ll res = 0;
        for (int i = pos; i; i -= lowbit(i))
            res += Query(rt[i], 1, n, k);
        return res; 
    }
    #undef lowbit
} bit;

void update(int x, int y, int n){
    if(fst[x])
        bit.add(x, fst[x], fst[x] - x, n);
    if(y)   
        bit.add(x, y, x - y, n);
    fst[x] = y;
}

int aa[100005];
set<int> st[100005];

inline set<int>::iterator nxt_it(set<int>::iterator it){
    return (++it);
}

inline set<int>::iterator pre_it(set<int>::iterator it){
    return (--it);
}

int main(){
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i)
        aa[i] = read();
    for (int i = 1; i <= n; i ++) {
        if (!st[aa[i]].empty()){
            fst[i] = *st[aa[i]].rbegin(); 
            bit.add(i, fst[i], i - fst[i], n);
        }
        st[aa[i]].insert(i);
    }
    int op, x, y;
    for (int I = 0; I < m; ++I){
        op = read(), x = read(), y = read();
        if (op == 1){
            set<int>::iterator it = st[aa[x]].find(x);
            if (nxt_it(it) != st[aa[x]].end())
                update(*nxt_it(it), (it == st[aa[x]].begin() ? 0 : *pre_it(it)), n);
            st[aa[x]].erase(x);
            aa[x] = y; 
            it = st[y].insert(x).first;
            update(x, (it == st[y].begin() ? 0 : *pre_it(it)), n);
            if(nxt_it(it) != st[y].end())
                update(*nxt_it(it), x, n);
        }
        else
            printf("%lld
", bit.qry(x, y, n));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/linzhengmin/p/10791022.html