• 暑假第一测


    题解: 第一题:找规律, 发现儿子减去父亲的编号是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关押罪犯
     
  • 相关阅读:
    怎么为学生布置作业
    新学期的第一节Android课
    RUCSE小组博客列表
    test
    个人最终总结
    黄金点小游戏的设计与实现
    WordCount 程序的实现
    阅读下面程序,请回答如下问题:
    Visual Studio 2015的安装和简单的单元测试
    构建之法--软件工程学习随笔之二
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9291745.html
Copyright © 2020-2023  润新知