zoukankan      html  css  js  c++  java
  • 2019.9.19模拟赛A组

    HOJ1034遭遇(2019.9.19模拟赛A组T1)

    404nofind

    题意

    lky要跳楼
    你需要一开始选择一座楼,开始跳楼。在第(i)座楼准备跳楼需要(c_i)的花费。每次可以跳到任何一个还没有跳过的楼上去。但跳楼是有代价的,每次跳到另外一座楼的代价是两座楼高度的差的绝对值,最后一次从楼上跳到地面上不需要代价(只能跳到地上一次)。求在代价不超过(T)的情况下,最多跳几次楼。(一座楼只能跳一次,且每次跳楼都要计算准备的花费)

    怎么做

    贪心+DP

    由题意可知,每次跳跃要消耗高度差的代价。这样如果反复横跳肯定是不优的,为了保证高度差的代价尽量小,我们应采用按照从高到低或从低到高的顺序跳楼。

    f[i][j]跳了j栋到i的最小代价
    DP阶段:跳到了i
    状态:跳了j栋
    转移方程:f[i][j] = min(f[i][j], f[k][j-1]);
    复杂度(O(n^3))
    其实是可以优化成(O(n^2))的,只是我不会。又要咕咕咕这个做法了

    代码

    #include <bits/stdc++.h>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename T>
    inline T poread()
    {
        T ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
        return ret;
    }
    template <typename Y>
    inline void poread(Y &ret)
    {
        ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    #define min(_x, _y) (_x > _y ? _y : _x)
    const int MAXN = 305;
    int f[MAXN][MAXN];
    struct node
    {
        int h, c;
        bool operator<(const node &it) const
        {
            return h < it.h;
        }
    } building[MAXN];
    #define h(_o) building[_o].h
    #define c(_o) building[_o].c
    int n, t;
    int main()
    {
        poread<int>(n);
        for (register int i = 1; i <= n; ++i)
            poread<int>(building[i].c);
        for (register int i = 1; i <= n; ++i)
            poread<int>(building[i].h);
        poread<int>(t);
        sort(building + 1, building + 1 + n);
        memset(f, 0x3f, sizeof(f));
        for (register int i = 1; i <= n; ++i)
            f[i][0] = 0;
        for (register int i = 1; i <= n; ++i)
        {
            for (register int j = 1; j <= i + 1; ++j)
            {
                for (register int k = 1; k < i; ++k)
                {
                    f[i][j] = min(f[i][j], f[k][j - 1] + h(i) - h(k) + c(k));
                }
            }
        }
        int ans = 0;
        for (register int i = n; ~i; --i)
        {
            for (register int j = 1; j <= n; ++j)
            {
                if (f[j][i] + c(j) <= t)
                {
                    printf("%d
    ", i + 1);
                    return 0;
                }
            }
        }
    }
    

    HOJ1035都市(2019.9.19模拟赛A组T2)(Luogu3540SQU-Squarks)

    (color{blue}{ ext{404nofind}})

    题意

    有n个数,给出两两之间的和,求这n个数的所有可能值。

    怎么做

    这是智商题
    考虑一个事情,如果给定三个数(a_1, a_2, a_3)分别相加的和,怎样求出这三个数呢?
    显然,我们可以算出来这三个数的和,即(frac{(a_1 + a_2)+(a_1+a_3)+(a_2+a_3)}{2} = a_1+a_2+a_3),并依次相减,即可得到(a_1, a_2, a_3)
    那么对于(n)个数{(a_1, a_2...a_n)}, 若我们钦定数列是有序的,我们可以判断出(a_1+a_2)以及(a_1+a_3),因为这两个分别是最小的以及第二小的数。

    证明:
    假设(a_1+a_2>a_x+a_y(x, y eq 1, 2))
    (ecause a_2<a_x)
    ( herefore a_1+a_2>a_2+a_y)
    (qquad quad a_1 > a_y)
    这与{(a_1, a_2...a_n)}有序不符,所以(a_1+a_2)是最小的,同理可证(a_1+a_3)第二小。

    此时我们已经知道了(a_1+a_2)以及(a_1+a_3),在剩下的情况中枚举(a_2+a_3),就可以求出(a_1, a_2, a_3)这三个数。
    在求得(a_1)后,我们便可枚举(a_1+a_k)是哪个数,并且判断该情况是否合法。以上两个枚举复杂度都是O((n)).
    关于如何判断是否合法,可以通过已知的数,进行求和,并判断这个情况下的和是否符合题目给出的值。这个复杂度是O((n))的。
    整体复杂度O((n^3))。

    放代码

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 305;
    int n, m, cnt;
    int a[45005];
    bool use[45005];
    int num[MAXN];
    struct node
    {
        int ans[MAXN];
        inline void print()
        {
            for (register int i = 1; i <= n; ++i)
                printf("%d ", ans[i]);
            putchar('
    ');
        }
        void operator=(int *s)
        {
            memcpy(ans, s, sizeof(ans));
        }
    } ans[MAXN];
    inline int find(const int &x)
    {
        int l = 1, r = m, mid, res;
        while (l <= r)
        {
            mid = (l + r) >> 1;
            if (a[mid] <= x)
            {
                res = mid, l = mid + 1;
            }
            else
            {
                r = mid - 1;
            }
        }
        return res;
    }
    inline void check(int x)
    {
        memset(use, 0, sizeof(use));
        int sum = a[1] + a[2] + a[x];
        if (sum & 1)
            return;
        sum >>= 1;
        num[1] = sum - a[x];
        num[2] = sum - a[2];
        num[3] = sum - a[1];
        use[1] = use[2] = use[x] = true;
        for (register int i = 3, k = 4; k <= n; ++k) //枚举a1 + ak
        {
            while (i <= m && use[i]) //判重
                ++i;
            if (i > m)
                return;
            num[k] = a[i] - num[1];
            use[i] = true;
            for (register int j = 2; j < k; ++j) //枚举a[x] + a[k]
            {
                if (num[j] > num[k]) //保证顺序
                    return;
                sum = num[j] + num[k];
                register int p = find(sum);
                if (a[p] != sum)
                    return;
                register int px = p;
                while (px && a[px] == a[p]) //找到相同数值中最前面的一个
                    --px;
                ++px;
                while (px <= m && use[px] && a[px] == a[p])
                    ++px;
                if (a[px] != a[p] || use[px])
                    return;
                p = px;
                use[p] = true;
            }
        }
        ++cnt;
        ans[cnt] = num;
    }
    int main()
    {
        scanf("%d", &n);
        m = (n * (n - 1)) / 2;
        for (register int i = 1; i <= m; ++i)
        {
            scanf("%d", &a[i]);
        }
        sort(a + 1, a + m + 1);
        for (register int i = 3; i <= m;) //枚举a2 + a3;
        {
            check(i);
            register int ii = i;
            while (a[ii] == a[i]) //去重
                ++ii;
            i = ii;
        }
        printf("%d
    ", cnt);
        for (register int i = 1; i <= cnt; ++i)
            ans[i].print();
    }
    

    小结

    考试的时候这个题只想到了通过三个数的和求出这三个数,应该考虑将其扩展进行枚举。

    HOJ1036街灯(2019.9.19模拟赛A组T3)

    404nofound

    题意

    街上的街灯亮起,指引向着远方的路。每个街灯上都有一个数,每次询问,第(l)个街灯到第(r)个街灯上的数模(p)等于(v)的有几个。

    咋做

    ({nsqrt{n}log{n}}) 在线做法

    这种题考虑分成部分处理。对于({q<100})的部分,它的模数不超过100,所以可以直接开一个桶(v_1[i][j])记录(i % p == j) 的数的出现位置,询问时查询出这个桶中有几个位置在(l,r)之间即可。由于数据范围较大,这个桶开成vector,保证不炸空间。
    对于剩下的部分,我们发现如果({a equiv v{pmod p} }), (a = p * i + v), 我们枚举(i),便可以找到所有符合询问要求的数。所以开一个桶(v_2[x]),放入所有(x)的出现位置,查询时枚举(i), 使 $ x = p*i+v (, 找到在)l,r(区间内有几个)x(,并对所有x的答案求和即为所求。<br>复杂度分析:每个询问,由于枚举)x(是)sqrt{n}(的,查询区间内的数二分左右端点是)log{n}(的,总体复杂度)O({nsqrt{n}log{n}})$。

    ({nsqrt{n}}) 离线做法

    和之前的做法差不多,只是要离线按照位置(sort)一下询问,处理(1) ~ (l-1)(1)~(r),答案为二者的差。由于不用二分,所以复杂度是({O(nsqrt{n})})

    Code

    这个是(O({nsqrt{n}log{n}}))在线的

    #include <bits/stdc++.h>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename T>
    inline T poread()
    {
        T ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
        return ret;
    }
    template <typename Y>
    inline void poread(Y &ret)
    {
        ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    const int MAXN = 105;
    int n, m;
    struct node
    {
        vector<int> v;
        inline int find(const int &x, int &rec)
        {
            register int l = 0, r = v.size() - 1, mid;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (v[mid] >= x)
                {
                    rec = mid;
                    r = mid - 1;
                }
                else
                {
                    l = mid + 1;
                }
            }
            return rec;
        }
        inline int finds(const int &x, int &rec)
        {
            register int l = 0, r = v.size() - 1, mid;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (v[mid] <= x)
                {
                    rec = mid;
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            return rec;
        }
        inline void push_back(const int &x)
        {
            v.push_back(x);
        }
    } v1[MAXN][MAXN], v2[10005];
    int a[100005];
    int main()
    {
    #ifdef lky233
        freopen("testdata.in", "r", stdin);
        freopen("testdata.out", "w", stdout);
    #endif
        poread(n);
        poread(m);
        for (register int i = 1; i <= n; ++i)
            poread(a[i]);
        for (register int i = 1; i <= n; ++i)
            v2[a[i]].push_back(i);
        for (register int i = 1; i <= 100; ++i)
        {
            for (register int j = 1; j <= n; ++j)
            {
                v1[i][a[j] % i].push_back(j);
            }
        }
        for (register int i = 1, l, r, p, v; i <= m; ++i)
        {
            poread(l), poread(r), poread(p), poread(v);
            if (p <= 100)
            {
                int ans1, ans2;
                ans1 = ans2 = -1;
                v1[p][v].find(l, ans1);
                if (ans1 == -1)
                {
                    puts("0");
                    continue;
                }
                v1[p][v].finds(r, ans2);
                if (ans2 == -1)
                {
                    puts("0");
                    continue;
                }
                printf("%d
    ", ans2 - ans1 + 1);
            }
            else
            {
                int pos = v, tot = 0;
                while (pos <= 10000)
                {
                    int ans1 = -1, ans2 = -1;
                    v2[pos].find(l, ans1);
                    // cerr << i << " " << ans1 << " ";
                    if (ans1 == -1)
                    {
                        pos += p;
                        continue;
                    }
                    v2[pos].finds(r, ans2);
                    // cerr << ans2 << endl;
                    if (ans2 == -1)
                    {
                        pos += p;
                        continue;
                    }
                    tot += (ans2 - ans1 + 1);
                    pos += p;
                }
                printf("%d
    ", tot);
            }
        }
        return 0;
    }
    

    这个是({O(nsqrt{n})})离线的

    #include <bits/stdc++.h>
    using namespace std;
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    #ifdef lky233
    #define nextchar getchar
    #endif
    template <typename T>
    inline T poread()
    {
        T ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
        return ret;
    }
    template <typename Y>
    inline void poread(Y &ret)
    {
        ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
    }
    #undef nextcar
    } // namespace fdata
    using fdata::poread;
    const int MAXN = 1e5 + 5;
    int n, m;
    int a[MAXN];
    int c[105][105];
    int cc[10005];
    struct node
    {
        int p, v, id;
        bool op;
        node() {}
        node(int _p, int _v, int _id, int _op) { p = _p, v = _v, id = _id, op = _op; }
    } que[MAXN];
    int nxt[MAXN << 1], head[MAXN << 1], tot;
    int ans[MAXN][2];
    int main()
    {
    #ifdef lky233
        freopen("testdata.in", "r", stdin);
        freopen("testdata.out", "w", stdout);
    #endif
        poread(n), poread(m);
        for (register int i = 1; i <= n; ++i)
            poread(a[i]);
        for (register int i = 1, l, r, p, v; i <= m; ++i)
        {
            poread(l), poread(r), poread(p), poread(v);
            que[++tot] = node(p, v, i, 0);
            nxt[tot] = head[l - 1];
            head[l - 1] = tot;
            que[++tot] = node(p, v, i, 1);
            nxt[tot] = head[r];
            head[r] = tot;
        }
        for (register int I = 1; I <= n; ++I)
        {
            ++cc[a[I]];
            for (register int j = 1; j <= 100; ++j)
                ++c[j][a[I] % j];
            for (register int i = head[I]; i; i = nxt[i])
            {
                register int p = que[i].p, v = que[i].v;
                if (p <= 100)
                {
                    ans[que[i].id][que[i].op] = c[p][v];
                }
                else
                {
                    register int tmp = 0;
                    for (register int j = v; j <= 10000; j += p)
                        tmp += cc[j];
                    ans[que[i].id][que[i].op] = tmp;
                }
            }
        }
        for (register int i = 1; i <= m; ++i)
            printf("%d", ans[i][1] - ans[i][0]), putchar('
    ');
    }
    

    附赠随机数据生成器。。。对拍好久。。。

    #include <bits/stdc++.h>
    using namespace std;
    int seed;
    int main()
    {
        freopen("testdata.out", "r", stdin);
        cin >> seed;
        srand(seed + time(0));
        freopen("testdata.in", "w", stdout);
        int n = (rand() - 1) % 20 + 1;
        int m = (rand() - 1) % 10 + 1;
        cout << n << " " << m << endl;
        for (register int i = 1; i <= n; ++i)
        {
            cout << ((rand() - 1) % 100 + 1) << " ";
        }
        cout << endl;
        for (register int i = 1; i <= m; ++i)
        {
            int l = (rand() - 1) % n + 1;
            int r = (rand() - 1) % n + 1;
            int p = (rand() - 1) % (200) + 1;
            int v = (rand() - 1) % n + 1;
            if (l > r)
                swap(l, r);
            cout << l << " " << r << " " << p << " " << v << endl;
        }
    }
    
  • 相关阅读:
    Python之路【第二篇】:Python基础(8)-Tuple元组
    Python之路【第二篇】:Python基础(7)-列表
    Python之路【第一篇】:Python基础(6)
    Python之路【第一篇】:Python基础(5)
    Python之路【第一篇】:Python基础(4)
    Python之路【第一篇】:Python基础(3)
    Python之路【第一篇】:Python基础(2)
    Python之路【第一篇】:Python基础(1)
    SQL Server优化50法
    四层和七层负载均衡的区别
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11558547.html
Copyright © 2011-2022 走看看