暑假第一测

题解: 第一题:找规律, 发现儿子减去父亲的编号是Fibonacci数列, 所以就两个儿子一起跳, 就像倍增一样

#include <bits/stdc++.h>

using namespace std;
#define ll long long
ll f[1005];
int main()
{
   // freopen("fibonacci.in", "r", stdin);
   // freopen("fibonacci.out", "w", stdout);
    int m;
    f[1] = 0, f[2] = 1, f[3] = 2;
    for(int i = 4; i <= 60; i++)f[i] = f[i-1] + f[i-2];
    scanf("%d", &m);
    int lst = 60;
    while(m--){
        ll a, b;
        scanf("%lld%lld", &a, &b);
        while(a != b){
            if(a < b)swap(a, b);
            int i;
            for(i = 60; i >= 0; i--)
                if(f[i] < a){
                    break;
                }
            a -= f[i];
        }
        printf("%lld
", a);
    }
    return 0;
}
View Code

第二题:我写的分块, 但用map代替的数组, 结果还跑的不如直接for循环,map一次操作log(n), 一定要谨慎用stl;

正解:

#include <bits/stdc++.h>

using namespace std;
const int M = 3*1e5 + 10;
const int N = 570;
int a[M];
vector <int> co[M];
 void read(int &x){
     int f = 1;x= 0;char c= getchar();
     while(c<'0'||c>'9'){if(c==-1)f=-1;c=getchar();}
     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     x*=f;
 }
int main()
{
//    freopen("color.in","r",stdin);
//    freopen("color.out","w",stdout);
   int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        read(a[i]);
        co[a[i]].push_back(i);
    }
    for(int i = 1; i <= n; i++)
        sort(co[i].begin(), co[i].end());
    while(m--){
        int opt, l, r, c;
        read(opt);
        if(opt == 1){
            read(l), read(r), read(c);
            int ans = upper_bound(co[c].begin(), co[c].end(), r) - lower_bound(co[c].begin(), co[c].end(), l);
            printf("%d
", ans);
        }
        else {
            read(l);
            if(a[l] == a[l+1])continue;
            (*lower_bound(co[a[l]].begin(), co[a[l]].end(), l))++;
            (*lower_bound(co[a[l+1]].begin(), co[a[l+1]].end(), l+1))--;
            swap(a[l], a[l+1]);
        }
    }
    return 0;
}
View Code

也可以主席树,按下标建,但只有70分;

// luogu-judger-enable-o2
#include <bits/stdc++.h>

using namespace std;
const int M = 3*1e5 + 10;
const int N = 1e6+5;
int n, a[M];
struct Node {
    Node *ls, *rs;
    int sum;
    void up(){
        sum = ls->sum + rs->sum;
    }
}pool[N*20], *zero, *tail = pool, *root[M];
void init(){
    zero = ++tail;
    root[0] = zero;
    zero->ls = zero->rs = zero;
    zero->sum = 0;
}
Node * newnode(){
    Node *nd = ++tail;
    nd->ls = nd->rs = zero;
    nd->sum = 0;
    return nd;
}
#define Ls nd->ls,l,mid
#define Rs nd->rs,mid+1,r
int query(int pos, Node *nd, int l = 1, int r = M){
    if(nd == zero)return 0;  
    if(l == r)return nd->sum;
    int mid = (l + r) >> 1;
    if(pos <= mid && nd->ls)return query(pos, Ls);
    if(pos > mid && nd->rs)return query(pos, Rs);
    return 0;
}

Node * modify(int pos, int val, Node *nd, int l = 1, int r = M){
    Node *nnd = newnode();
    if(l == r)
        nnd->sum = nd->sum + val;
    else {
        int mid = (l + r) >> 1;
        int ans  = 0;
        if(pos <= mid){
            nnd->ls = modify(pos, val, Ls);
            nnd->rs = nd->rs;
        }
        else {
            nnd->ls = nd->ls;
            nnd->rs = modify(pos, val, Rs);
        }
        nnd->up();    
    }
    return nnd;
}
int main()
{
    int m;
    init();
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        root[i] = modify(a[i], 1, root[i-1]);
        //printf("LL
");
    }
    while(m--){
        int opt, l, r, c;
        scanf("%d", &opt);
        if(opt == 1){
            scanf("%d%d%d", &l, &r, &c);
            printf("%d
", query(c, root[r]) - query(c, root[l-1]));
        }
        else {
            scanf("%d", &l);
            root[l] = modify(a[l], -1, root[l]);
            root[l] = modify(a[l+1], 1, root[l]);
            swap(a[l], a[l+1]);
        }
    }
    return 0;
}
View Code

第三题:

对于k==1, 这道题贪心,因为前面要装的少,所以倒着往多装, 对于平方, 枚举看是否有冲突, 也就512^2

对于k == 2, 如果a[j]重复出现,先判定它本身是否影响; 不然看它是否与其他数冲突;

对于一个数它最多可以和集合中两个数冲突, vis[a[j]] 表示他在一个组合中上部分, dvis[a[j]]表示他在一个组合中下部分,

贴的std, 四组不过

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

#define N 131073

int n, m = 0, K;
int a[N], b[N];
bool vis[N], dvis[N], issqr[N * 2];
int f[N * 2];

int getf(int x) {return f[x] > 0 ? (f[x] = getf(f[x])) : x;}

void merge(int u, int v) {
    u = getf(u), v = getf(v);
    if (u != v) {
        f[u] += -1;
        f[v] = u;
    }
}

bool check(int u, int v) {
    int s1 = getf(u), s2 = getf(u + N);
    int t1 = getf(v), t2 = getf(v + N);
    if (s1 == t1) return 1;
    if (s2 == t2) return 1;
    merge(s1, t2); merge(s2, t1);
    return 0;
}

void solve_1() {
    for (int i = n, j = n; i;) {
        for (bool flag = 1; j; j--) {
            for (int k = 1; k * k - a[j] < N; k++) {
                if (k * k - a[j] <= 0) continue;
                if (vis[k * k - a[j]]) {flag = 0; break;} 
            }
            if (!flag) break;
            vis[a[j]] = 1;
        }
        if (!j) break;
        b[++m] = j;
        for ( ; i > j; i--) vis[a[i]] = 0;
    }
}

void solve_2() {
    memset(f, -1, sizeof f);
    for (int i = 1; i * i < 2 * N; i++) issqr[i * i] = 1;
    for (int i = n, j = n; i;) {
        for (bool flag = 1; j; j--) {
            if (vis[a[j]]) {
                if (issqr[a[j] + a[j]]) {
                    if (dvis[a[j]]) break;
                    for (int k = 1; k * k - a[j] < N; k++) {
                        if (k * k - a[j] <= 0) continue;
                        if (vis[k * k - a[j]] && k * k != a[j] * 2) {
                            flag = 0; break;
                        } 
                    }
                    if (!flag) break;
                    dvis[a[j]] = 1;
                }
            }
            else {
                for (int k = 1; k * k - a[j] < N; k++) {
                    if (k * k - a[j] <= 0) continue;
                    if (vis[k * k - a[j]]) {
                        if (check(k * k - a[j], a[j])) {flag = 0; break;}
                    } 
                }
                if (!flag) break;
                vis[a[j]] = 1;
            }
        }
        if (!j) break;
        b[++m] = j;
        for ( ; i > j; i--) f[a[i]] = f[a[i] + N] = -1, vis[a[i]] = 0, dvis[a[i]] = 0;
    }
}

int main() {
    ///freopen("division.in", "r", stdin);
    //freopen("division.out", "w", stdout);
    scanf("%d%d", &n, &K);
    for (int i = 1; i <= n; i++) scanf("%d", a + i);
    if (K == 1) solve_1();
    else solve_2();
    printf("%d
", m + 1);
    for (int i = m; i; i--) printf("%d ", b[i]);
    putchar('
');
    return 0;
}
View Code
•第一题考察:观察性质,求斐波那契数列。
•相似题目:(嗨呀我还真没找到类似的 NOIp 题目)
•第二题考察:排序,二分查找。(或者可以使用高级数据结构)
•相似题目:NOIp 2012借教室
•第三题考察:观察性质,并查集,复杂度分析。
•相似题目:NOIp 2010关押罪犯
 
原文地址:https://www.cnblogs.com/EdSheeran/p/9291745.html