zoukankan      html  css  js  c++  java
  • 近期刷题记录表

    9月14日:  

    luogu P1627 [CQOI2009]中位数 

    题意:给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。

    题解:根据中位数的性质,将大于b的数记为1,小于b的数记为-1,区间和为0的奇数序列即符合题意,再计数即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, b, a[N], lsum[N], rsum[N]; 
    int l[N], r[N], minn = N, maxx = 0;
    int pos;
    ll ans = 0;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        n = read(); b = read();
        rep(i, 1, n){ 
            a[i] = read();
            if(a[i] < b) a[i] = -1;
            if(a[i] == b) a[i] = 0, pos = i;
            if(a[i] > b) a[i] = 1;
        }
        rep(i, pos+1, n) rsum[i] = rsum[i-1] + a[i], minn = min(minn, rsum[i]+n);
        per(i, pos-1, 1) lsum[i] = lsum[i+1] + a[i], minn = min(minn, lsum[i]+n);
        l[n] = r[n] = 1;
        rep(i, pos+1, n) r[rsum[i]+n]++;
        per(i, pos-1, 1) l[lsum[i]+n]++;
        maxx = 2*n-minn;
        rep(i, minn, maxx){
            ans += (ll)l[i] * r[2*n-i];
        } 
        printf("%lld
    ", ans);
        return 0;
    }
    View Code

    luogu P3407 散步

    题意:数轴上有n个人,每秒钟在给定的方向(向东或向西)移动一个距离,当一个人与一个人相遇时两人不再移动,求t秒后,指定m个人所在的位置。

    题解:预处理出相遇点,然后二分答案与pos+t进行比较即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    const ll inf = 4557430888798830399;
    ll n, t, q;
    ll s[N], k = 0;
    struct people{ll pos, dic, id; } a[N];
    bool mycmp(people a, people b) {return a.pos < b.pos; }
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        n = read(); t = read(); q = read();
        rep(i, 1, n) a[i].pos = read(), a[i].dic = read(), a[i].id = i;
        sort(a+1, a+n+1, mycmp);
        rep(i, 2, n){
            if(a[i].dic == 2 && a[i-1].dic == 1) s[++k] = (a[i].pos+a[i-1].pos)>>1;
        }  
        s[0] = -inf, s[k+1] = inf;
        rep(i, 1, q){
            ll x = read();
            ll posx = a[a[x].id].pos, flag = a[a[x].id].dic;
            ll l = 1, r = k, mid;
            while(l < r){
                mid = (l+r)>>1;
                if(flag == 1){
                    if(s[mid] < posx) l = mid+1;
                    if(s[mid] > posx) r = mid;
                }
                if(flag == 2){
                    if(mid == l) mid++;
                    if(s[mid] < posx) l = mid;
                    if(s[mid] > posx) r = mid-1;
                }
            }
            mid = l;
            if(s[mid] < posx && flag == 2){
                if(s[mid+1] < posx && s[mid+1] != inf) mid++;
            }
            if(s[mid] > posx && flag == 1){
                if(s[mid-1] > posx && s[mid-1] != inf) mid--; 
            }
            if(flag == 1){
                if(s[mid] > posx+t && s[mid] > posx) printf("%lld
    ", posx+t);
                else if(s[mid] < posx) printf("%lld
    ", posx+t);
                else if(s[mid] < posx+t && s[mid] > posx) printf("%lld
    ", s[mid]);
                else printf("%lld
    ", s[mid]);
            }
            if(flag == 2){
                if(s[mid] < posx-t && s[mid] < posx) printf("%lld
    ", posx-t);
                else if(s[mid] > posx-t && s[mid] < posx) printf("%lld
    ", s[mid]);
                else if(s[mid] > posx) printf("%lld
    ", posx-t); 
                else printf("%lld
    ", s[mid]);
            }
        }
        return 0;
    }
    View Code

     9月15日:

    HLOJ 糖果传递

    题意:有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

    题解:环形均分纸牌,只要做过均分纸牌,稍稍分析一下就可以得出结论。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[N], b[N], tot = 0, sum[N];
    ll ans, cnt;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read(), tot += a[i];
        tot /= n;
        rep(i, 1, n) b[i] = a[i]-tot;
        rep(i, 1, n) sum[i] = sum[i-1] + b[i];
    }
    void work(){
        nth_element(sum+1, sum+(n+1)/2, sum+n+1);
        cnt = sum[(n+1)/2];
        rep(i, 1, n) ans += abs(sum[i]-cnt);
    }
    void print(){
        printf("%lld
    ", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

     HLOJ The Pilots Brothers refrigerator

    题意:给出4×4共16个门把手,改变一个门把手(打开或关闭)需要同时改变同行同列的门把手,当所有门把手都打开时才能打开门。+代表关,-代表开。

    题解:要使一个为'+'的符号变为'-',必须其相应的行和列的操作数为奇数;可以证明,如果'+'位置对应的行和列上每一个位置都进行一次操作,则整个图只有这一'+'位置的符号改变,其余都不会改变.

    将所有的行和列的位置都加1后,在将其模2之前,对给定的数组状态,将所有的位置操作其所存的操作数个次数,举例,如果a[i][j]==n,则对(i,j)操作n次,当所有的操作完后,即全为‘-’的数组。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    char s[10][10];
    int a[10][10], vis[10][10];
    int ansx[N], ansy[N], ans = 0, h = 0;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        rep(i, 1, 4) rep(j, 1, 4) cin >> s[i][j];
        rep(i, 1, 4) rep(j, 1, 4){
            if(s[i][j] == '+') {
                a[i][j] ^= 1;
                rep(k, 1, 4) a[i][k] ^= 1;
                rep(k, 1, 4) a[k][j] ^= 1; 
            }    
        }
        rep(i, 1, 4) rep(j, 1, 4){
            if(a[i][j]) {
                ans++;
                ansx[++h] = i;
                ansy[h] = j;
            }
        }
        printf("%d
    ", ans);
        rep(i, 1, h) printf("%d %d
    ", ansx[i], ansy[i]);
        return 0;
    }
    View Code

     HLOJ 占卜DIV

    题意(稍稍有点长):

    lyd学会了使用扑克DIY占卜。方法如下:一副去掉大小王的扑克共52张,打乱后均分为13堆,编号1~13,每堆4张,其中第13堆称作“生命牌”,也就是说你有4条命。这里边,4张K被称作死神。

     初始状态下,所有的牌背面朝上扣下。

     流程如下:

     1.抽取生命牌中的最上面一张(第一张)。

     2.把这张牌翻开,正面朝上,放到牌上的数字所对应编号的堆的最上边。(例如抽到2,正面朝上放到第2堆牌最上面,又比如抽到J,放到第11堆牌最上边,注意是正面朝上放)

     3.从刚放了牌的那一堆最底下(最后一张)抽取一张牌,重复第2步。(例如你上次抽了2,放到了第二堆顶部,现在抽第二堆最后一张发现是8,又放到第8堆顶部.........)

     4.在抽牌过程中如果抽到K,则称死了一条命,就扔掉K再从第1步开始。

     5.当发现四条命都死了以后,统计现在每堆牌上边正面朝上的牌的数目,只要同一数字的牌出现4张正面朝上的牌(比如4个A),则称“开了一对”,当然4个K是不算的。

     6.统计一共开了多少对,开了0对称作"极凶",1~2对为“大凶”,3对为“凶”,4~5对为“小凶”,6对为“中庸”,7~8对“小吉”,9对为“吉”,10~11为“大吉”,12为“满堂开花,极吉”。

    题解:清一色的模拟题,按照题意直接模拟,注意一下细节。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int s[14][5], k[14], sum[15];
    int ans = 0;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    
    int main(){
        rep(i, 1, 13) rep(j, 1, 4) {
            char ch;
            cin >> ch; 
            if(ch == 'A') s[i][j] = 1;
            else if(ch == '0') s[i][j] = 10;
            else if(ch == 'J') s[i][j] = 11;
            else if(ch == 'Q') s[i][j] = 12;
            else if(ch == 'K') s[i][j] = 13;
              else s[i][j] = (int)(ch-'0');
        }
          rep(i, 1, 13) k[i] = 4;
          rep(i, 1, 4){
            int x = s[13][i];
            while (x != 13) {
                sum[x]++;
                  x = s[x][k[x]--]; 
            }
          }
          rep(i, 1, 14) 
            if (sum[i] == 4) ans++;
        printf("%d
    ", ans);
        return 0;
    }
    View Code

     HLOJ solders

    题意:这个题目的意思是给你n个士兵在棋盘里的坐标,要你将他们排成连续的一行(即与x轴平行),问你最少要将这些士兵移动多少步。

    题解:y坐标取中位数,x坐标转换为右值相等即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, sum = 0, totx = 0, toty = 0;
    int x[N], y[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        n = read();
        rep(i, 1, n) x[i] = read(), y[i] = read();
        sort(y+1, y+n+1);
        toty = y[n/2+1];
        sort(x+1, x+n+1);
        rep(i, 1, n) x[i] -= (i-1);
        sort(x+1, x+n+1);
        totx = x[n/2+1];
        rep(i, 1, n) sum += abs(totx-x[i]) + abs(toty-y[i]);
        printf("%d
    ", sum);
        return 0;
    }
    View Code

    HLOJ Sumdiv

    题意:求A的B次方mod 1e9 + 7 的值。

    题解:对A进行质因子分解,然后推出计算公式,等比数列求和后,求个逆元,再累乘取模即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const ll mod = 1000000007;
    const int N = 1e6 + 50;
    ll a, b, p[N], c[N], k = 0;
    ll ans = 1;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void divide(ll x){
        rep(i, 2, sqrt(x)) 
            if(x % i == 0) {
                p[++k] = i; c[k] = 0;
                while(x % i == 0) x /= i, c[k]++;
            }
        if(x > 1) p[++k] = x, c[k] = 1;
    }
    ll pow(ll a, ll b){
        ll ans = 1;
        while(b){
            if(b & 1) ans = (ans*a)%mod;
            b >>= 1;
            a = a*a%mod;
        }
        return ans;
    }
    void work(){
        rep(i, 1, k){
            ans = ans*( ( pow( p[i], b*c[i]+1 )-1 )%mod * pow( p[i]-1, mod-2 )%mod)%mod;
        }
    }
    int main(){
        a = read(); b = read();
        divide(a);    
        work();
        if(a == 0) printf("0
    ");
        else printf("%lld
    ", (ans+mod)%mod);
        return 0;
    }
    View Code

     HLOJ 防线

    题意:用三个整数S,E 和D 来描述一组防具,即这一组防具布置在防线的S,S + D,S + 2D,...,S + KD(K∈Z,S + KD≤E,S + (K + 1)D>E)位置上。求某个具有奇数个防具的位置。

    题解:整体为二分的思想,二分坐标,l为0, r为最远的点,因为最多只有一个奇数,所以每次二分找区间的数字和是不是奇数即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    const ll inf = 9984432123;
    ll n, t;
    ll e[N],s[N],d[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    ll calc(ll x){
        ll res = 0;
        for(int i = 1;i <= n;i++)
            if(s[i] <= x) res = res+(min(e[i], x)-s[i])/d[i]+1;
        return res;
    }
    int main(){
        t = read();
        while(t--){
            n = read();
            ll l = 0, r;
            for(int i = 1;i <= n;i++) s[i] = read(), e[i] = read(), d[i] = read(), r = max(r, e[i]);
            ll ans = 0;
            while(l <= r){
                ll mid = (l+r)>>1;
                if(calc(mid) & 1) r = mid-1, ans = mid;
                else l = mid+1;
            }
            if(!ans) puts("There's no weakness.");
            else printf("%lld %lld
    ", ans, calc(ans)-calc(ans-1));
        }
        return 0;
    }
    View Code

     HLOJ to the max

    题意:给定一个n*n的矩阵,求其最大的子矩阵的数字和。(n <= 100)

    题解:大水题,预处理前缀和,直接枚举计算,取最大值即可。                                                                                                                                                                      

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[3010][3010];
    ll f[3010][3010], ans = 0;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) rep(j, 1, n) a[i][j] = read();
        f[1][1] = a[1][1];
        rep(i, 1, n){  
            f[i][1] = f[i-1][1] + a[i][1]; 
            rep(j, 2, n){
                f[i][j] = f[i-1][j] + f[i][j-1] + a[i][j] - f[i-1][j-1];
            }
        }
    }
    void work(){
        ans = a[1][1];
        rep(i, 1, n) rep(j, 1, n) rep(p, i, n) rep(q, j, n){
            ll sum = f[p][q] - f[i-1][q] - f[p][j-1] + f[i-1][j-1];
            ans = max(ans, sum);
        }
    }
    void print(){
        printf("%lld
    ", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    HLOJ Sunscreen

    题意:

    奶牛们计划着去海滩上享受日光浴。为了避免皮肤被阳光灼伤,所有C(1 <= C <= 2500)头奶牛必须在出门之前在身上抹防晒霜。第i头奶牛适合的最小和最 大的SPF值分别为minSPF_i和maxSPF_i(1 <= minSPF_i <= 1,000; minSPF_i <= maxSPF_i <= 1,000)。如果某头奶牛涂的防晒霜的SPF值过小,那么阳光仍然能 把她的皮肤灼伤;如果防晒霜的SPF值过大,则会使日光浴与躺在屋里睡觉变得 几乎没有差别。为此,奶牛们准备了一大篮子防晒霜,一共L(1 <= L <= 2500)瓶。第i瓶 防晒霜的SPF值为SPF_i(1 <= SPF_i <= 1,000)。瓶子的大小也不一定相同,第i 瓶防晒霜可供cover_i头奶牛使用。当然,每头奶牛只能涂某一个瓶子里的防晒霜 ,而不能把若干个瓶里的混合着用。 请你计算一下,如果使用奶牛们准备的防晒霜,最多有多少奶牛能在不被灼 伤的前提下,享受到日光浴的效果?

    简明一点就是:给你若干线段和点,每个点可以与包含这个点的线段匹配,求最大匹配数。

    题解:线段按右端点排序,防晒霜按防护值排序,之后进行贪心即可,注意防晒霜的数量。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int k, c, ans = 0;
    struct cow{ int l, r; } a[N];
    struct node{ int l, r; } b[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    bool cmp1(cow x, cow y){return x.l > y.l;}
    bool cmp2(node x, node y){return x.l > y.l;}
    int main(){
        c = read(); k = read();
        rep(i, 1, c) a[i].l = read(), a[i].r = read();
        rep(i, 1, k) b[i].l = read(), b[i].r = read();
        sort(a+1, a+c+1, cmp1);
        sort(b+1, b+k+1, cmp2);
        rep(i, 1, c) rep(j, 1, k){
            if(b[j].l >= a[i].l && b[j].l <= a[i].r && b[j].r) {
                ans++; b[j].r--;
                break; 
            }
        }
        printf("%d
    ", ans);
        return 0; 
    }
    View Code

    HLOJ Task

    题意:有n个机器,m个任务。每个机器至多能完成一个任务。对于每个机器,有一个最大运行时间xi和等级yi,对于每个任务,也有一个运行时间xj和等级yj。只有当xi>=xj且yi>=yj的时候,机器i才能完成任务j,并获得500xj+2yj金钱。问最多能完成几个任务,当出现多种情况时,输出获得金钱最多的情况。

    题解:根据任务去选择机器,任务从小到大排列好,遍历的时候。每次先把所有时间大于该任务的机器按照等级存储下来,同等级的机器是等效的,因为只要能完成任务都是等效的,然后取其中恰好大于等于该任务的等级的机器,正确性可以证明。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, m, maxx = 0, ans1, p[N];
    ll ans2;
    struct node{ int x, y; } a[N];
    struct task{ int x, y;} b[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    bool mycmp1(node x, node y){ return (x.x > y.x) || (x.x == y.x && x.y > y.y ); }
    bool mycmp2(task x, task y){ return (x.x > y.x) || (x.x == y.x && x.y > y.y ); }
    void init(){
        n = read(); m = read();
        rep(i, 1, n) a[i].x = read(), a[i].y = read();
        rep(i, 1, m) b[i].x = read(), b[i].y = read();
    }
    void work(){
        sort(a+1, a+n+1, mycmp1);
        sort(b+1, b+m+1, mycmp2);
        int j = 1;
        rep(i, 1, m){
            while(j <= n && a[j].x >= b[i].x){
                p[a[j].y] ++;
                j++;
            }
            rep(k, b[i].y, 100){
                if(p[k]){
                    p[k] --;
                    ans1++; ans2 += (ll)b[i].x*500 + b[i].y * 2;
                    break;
                }
            }
        }
    }
    void print(){
        printf("%d %lld
    ", ans1, ans2);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    9月16日

    HLOJ 货仓选址

    题意:在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

    题解:大水题,先按坐标排序,取中位数为货仓地址,直接计算即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[N], ans = 0, pos;  
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read();
        sort(a+1, a+n+1); 
    }
    void work(){
        pos = a[n/2+1];
        rep(i, 1, n) ans += (ll)abs(a[i] - pos);
    }
    void print(){
        printf("%lld
    " , ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    HLOJ Corral the Cows

    题意:约翰打算建一个围栏来圈养他的奶牛.作为最挑剔的兽类,奶牛们要求这个围栏必须是正方形的,而且围栏里至少要有(1<=C< =500)个草场,来供应她们的午餐. 约翰的土地上共有C<=N<=500)个草场,每个草场在一块1x1的方格内,而且这个方格的 坐标不会超过10000.有时候,会有多个草场在同一个方格内,那他们的坐标就会相同. 告诉约翰,最小的围栏的边长是多少?

    题解:考虑将坐标离散化,然后求二维前缀和,由于N<=500,所以离散化后最多也只有1000个点,检验时,我们枚举正方形的左上角,用二分求出它的右下角,然后,判断正方形内是否有大于C的草量。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    const int str = 10000;
    struct node{ int x, y; } a[N];
    int f[3010][3010];
    int n, c, minn = N, maxx = 0, ans = 0; 
    int px[N], py[N];
    int bx[N], by[N], xc, yc;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    bool mycmp(node a, node b){ return a.x < b.x; }
    void init(){
        c = read(), n = read();
        rep(i, 1, n) a[i].x = read(), a[i].y = read(), px[a[i].x]++, py[a[i].y]++;
        rep(i, 1, str) {
            if(px[i]) bx[++xc] = i;
            px[i] = xc;
            if(py[i]) by[++yc] = i;
             py[i] = yc;
        }
        rep(i, 1, n) f[px[a[i].x]][py[a[i].y]]++;
        rep(i, 1, xc) rep(j, 1, yc){
            f[i][j] += f[i-1][j] + f[i][j-1] - f[i-1][j-1];
        }
    }
    bool check(int x){
        rep(i, px[x], xc) rep(j, py[x], yc){
            int k = 0, l = 0;
            if (bx[i] - x >= 0) k = px[bx[i] - x];
            if (by[j] - x >= 0) l = py[by[j] - x];
            if (f[i][j] - f[k][j] - f[i][l] + f[k][l] >= c)
                return 1;
        }
        return 0;
    }
    void work(){
        int l = 1, r = str;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) r = mid;
            else l = mid + 1;
        }
        ans = l;
    }
    void print(){
        printf("%d
    ", ans);
    } 
    int main(){
        init();
        work();
        print(); 
        return 0;
    }
    View Code

    HLOJ Stall Reservation

    题意:给出n个区间,第i个区间表示为[li,ri],询问把这些最少的分组数,使得每组内每个区间相离,1<=N<=50,000

    题解:按左端点排序

    现在来考虑第i个区间的决策点,对于能分进的组j,必然是aj<lj,第i个区间才能被分进去,但是选哪一个组,按照朴素的思想,必然是选aj最小的或者最大的,因为是按左端点排序,后面的区间左端点必然增大,于是前面区间能分进的组,后面的区间也能分进,于是无论选哪一个组都无所谓,如果不能选,必然要新开一个组。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    struct cow{ int l, r, id; } a[N];
    int n, k = 0, f[N];
    priority_queue < pii, vector< pii >, greater< pii > > q;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    bool mycmp(cow a, cow b){ return (a.l < b.l || (a.l == b.l && a.r < b.r)); }
    void init(){
        n = read();
        rep(i, 1, n) a[i].l = read(), a[i].r = read(), a[i].id = i;
    } 
    void work(){
        sort(a+1, a+n+1, mycmp);
        q.push(mp(a[1].r, ++k));
        f[a[1].id] = k;
        rep(i, 2, n) {
            if(a[i].l > q.top().first) {
                int x = q.top().second;
                q.pop();
                f[a[i].id] = x;
                q.push(mp(a[i].r, x));
            }
            else {
                f[a[i].id] = ++k;
                q.push(mp(a[i].r, k));
            }
        }
    }
    void print(){
        printf("%d
    ", k);
        rep(i, 1, n) printf("%d
    ", f[i]);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    HLOJ Ultra-QuickSort

    题意:给定一个序列,求这个序列的逆序对数。

    题解:模板题,直接树状数组求逆序对就莫得了。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[N], c[N];
    ll lowbit(ll x){ return x&(-x);}
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void add(ll k, ll v){ while(k <= N) c[k] += v, k += lowbit(k);  }
    ll sum(ll k){
        ll ans = 0;
        while(k) ans += c[k], k -= lowbit(k);
        return ans;
    }
    void init(){
        while(~scanf("%lld", &n)){
            if(!n) break;
            ll ans = 0;
            memset(c, 0, sizeof(c));
            rep(i, 1, n) a[i] = read();    
            per(i, n, 1){
                if(a[i] == 0) {
                    ans += (ll)i-1;
                    continue;
                }
                ans += (ll)sum(a[i]-1);
                add(a[i], 1); 
            }    
            printf("%lld
    ", ans);
        }
    }
    int main(){
        init();
        return 0;
    }
    View Code

    HLOJ 奇数码问题

    题意:在一个n*n的网格中进行,其中n为奇数,1个空格和1~n*n-1这n*n-1个数恰好不重不漏地分布在n*n的网格中。空格移动的规则与八数码游戏相同,实际上,八数码就是一个n=3的奇数码游戏。现在给定两个奇数码游戏的局面,请判断是否存在一种移动空格的方式,使得其中一个局面可以变化到另一个局面。

    题解:当此表达式成立时,状态可达:(状态1奇偶性==状态2奇偶性)==(空格距离%2==0)。若两个状态的可相互到达,则有,两个状态的逆序奇偶性相同且空格距离为偶数,或者,逆序奇偶性不同且空格距离为奇数数。否则不能。逆序对用树状数组求。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, a[N], c[N];
    int lowbit(int x){ return x&(-x);}
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void add(int k, int v){ while(k <= n) c[k] += v, k += lowbit(k);  }
    int sum(int k){
        int ans = 0;
        while(k) ans += c[k], k -= lowbit(k);
        return ans;
    }
    int work(){
        memset(c, 0, sizeof(c));
        int ans = 0;
        rep(i, 1, n){
            a[i] = read();
            if(!a[i]) continue;
            ans += sum(n) - sum(a[i]);
            add(a[i], 1);
        }
        return ans&1;
    }
    void init(){
        while(~scanf("%d", &n)){
            n *= n;
            if(work() == work()) printf("TAK
    ");
            else printf("NTE
    ");
        }
    }
    int main(){
        init();
        return 0;
    }
    View Code

    HLOJ Running Median

    题意:你需要写一个程序,读入一个整数序列(在int范围内),每读入奇数个数后输出当前的中位数。

    题解:考虑用两个堆来维护,一个大根堆一个小根堆。每次比较两个堆的堆顶,如果不相等就交换堆顶,否则堆顶即为所要求的中位数。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int t, n, m, k;
    priority_queue < int, vector<int>, greater<int> > x;
    priority_queue < int, vector<int>, less<int> > y;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        t = read();
        while(t--){
            m = read(); n = read();
            printf("%d %d
    ", m, n/2+1);
            k = read();
            while(x.size()) x.pop();
            while(y.size()) y.pop();
            printf("%d ", k);
            y.push(k);
            rep(i, 2, n){
                k = read();
                if(k > y.top()) x.push(k);
                else y.push(k);
                while(abs(x.size()-y.size()) > 1){
                    if(x.size() > y.size()){
                        y.push(x.top());
                        x.pop();
                    }
                    else {
                        x.push(y.top());
                        y.pop();
                    }
                }
                if(i & 1){
                    if(y.size() > x.size()) printf("%d ", y.top());
                    else printf("%d ", x.top());
                }
                if(i % 20 == 19) printf("
    ");
            }
            printf("
    ");
        }    
        return 0;
    }
    View Code

    HLOJ 七夕祭

    题意:有一个会场由N排M列共计N×M个摊点组成。但是小LL只对其中的一部分摊点感兴趣。他预先联系了会场的负责人,希望能够通过恰当地布置会场,使得各行中他感兴趣的摊点数一样多,并且各列中他感兴趣的摊点数也一样多。但是摊点已经随意布置完毕了,如果想满足小LL的要求,唯一的调整方式就是交换两个相邻的摊点。两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上,每一行或每一列的第一个位置和最后一个位置也算作相邻。现在小LL想知道他的两个要求最多能满足多少个。在此前提下,至少需要交换多少次摊点。

    题解:类似糖果传递,设 bi 的前缀和为 si。如果从第 k 个位置开始,那么第 i 堆和第 i+1 堆交换的纸牌数就是 |si-sk|。总代价就是|s1-sk|+|s2-sk|+|s3-sk|+……+|sn-sk|。发现什么了?当 sk 是 s1~sn 中位数的时候,上式有最小值!所以把 si 排序后,令 sk=s[(n+1)/2],计算代价即可。时间复杂度 O(nlogn),预计得分 100 分。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, m, t, a[N], b[N];
    ll ans = 0;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read(); m = read(); t = read();
        rep(i, 1, t){
            int x = read(), y = read();
            a[x]++, b[y]++; 
        }
        if((t % n != 0) && (t % m != 0)){
            puts("impossible");
            exit(0);
        }
    }
    void work(){
        rep(i, 1, n) a[i] -= t/n;
        rep(i, 1, m) b[i] -= t/m;
        if(t % n == 0){
            rep(i, 2, n) a[i] += a[i-1];
            sort(a+1, a+n+1);
            rep(i, 1, n) ans += (ll)abs(a[i] - a[(n+1)/2]);
        }
        if(t % m == 0){
            rep(i, 2, m) b[i] += b[i-1];
            sort(b+1, b+m+1);
            rep(i, 1, m) ans += (ll)abs(b[i]-b[(m+1)/2]);
        }
    }
    void print(){
        if(t % n != 0) printf("column ");
        else {
            if(t % m != 0) printf("row ");
            else printf("both ");
        }
        printf("%lld
    ", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    9月17日

    HLOJ Color a Tree

    题意:有一棵树,每个节点都有一个代价基值Ci。现在要给每个点染色,第一个染根节点,其余的节点染色的时候其父节点必须已染色。每个节点染色会用掉一个时间单位,每个节点染色的代价是染完此节点时的总时间T*Ci。问染完全部节点所需要的最小代价。

    题解:每次找到一个权值最大的节点,如果它是根节点,则首先对它染色,否则的话我们可以得出一个结论,在对它的父亲已经染色的情况下,立刻给它染色是最优的。现在重点讨论第二种情况,当它不是根节点时,我们如果对它父亲染了色,则一定会立刻对它染色,所以可以把它和它父亲合并为同一个节点,它和它父亲的儿子都成为了新节点的儿子,它的父亲的父亲则是新节点的父亲。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, root, a[N], ans;
    int head[N], cnt = 0;
    struct node{ 
        int to, next, fa, t;
        double v; 
    } e[N];
    void add(int x, int y){
        cnt ++; 
        e[cnt].to = y;
        e[cnt].next = head[x];
        head[x] = cnt;
    }
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int get(){
        int res = -1;
        double sum = 0;
        rep(i, 1, n) {
            if(i != root && sum < e[i].v){
                sum = e[i].v;
                res = i;
            }
        }
        return res;
    }
    void init(){
        n = read(); root = read(); 
        rep(i, 1, n) a[i] = read(), e[i].v = a[i], ans += a[i], e[i].t = 1;
        rep(i, 1, n-1){
            int xx, yy;
            xx = read(); yy = read();
            add(xx, yy);
            e[yy].fa = xx;
        }
    }
    void work(){
        rep(i, 1, n-1){
            int u = get();
            ans += a[u] * e[e[u].fa].t;
            e[u].v = -1;
            rep(j, 1, n) if (e[j].fa == u) e[j].fa = e[u].fa;
            a[e[u].fa] += a[u];
            e[e[u].fa].t += e[u].t;
            e[e[u].fa].v = (double) a[e[u].fa] / e[e[u].fa].t;
        }    
    }
    void print(){
        printf("%d
    ", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    HLOJ 兔子与兔子

    题意:很久很久以前,森林里住着一群兔子。有一天,兔子们想要研究自己的 DNA 序列。我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母),然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。注意两个兔子一模一样只可能是他们的 DNA 序列一模一样。

    题解:Hash表模板题,用Hash表存储前缀DNA序列。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    char s[N];
    int n, q;
    unsigned long long f[N], p[N]; 
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        scanf("%s", s+1); q = read();
        n = strlen(s+1); 
        p[0] = 1;
        rep(i, 1, n) {
            f[i] = f[i-1] * 131 + (s[i]-'a'+1);
            p[i] = p[i-1] * 131;
        }
    }
    void work(){
        rep(i, 1, q){
            int l1, l2, r1, r2;
            l1 = read(); r1 = read(); l2 = read(); r2 = read();
            if(f[r1] - f[l1-1] * p[r1-l1+1] == f[r2] - f[l2-1] * p[r2-l2+1]){
                puts("Yes");
            }
            else puts("No");
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    View Code

    HLOJ 最大子序和

    题意:输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。

    题解:对序列进行单调队列维护即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, m, a[N], sum[N];
    ll q[N], ans = 0;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read(); m = read();
        rep(i, 1, n) a[i] = read(), sum[i] = sum[i-1] + a[i];
    }
    void work(){
        int l = 1, r = 1;
        q[1] = 0;
        rep(i, 1, n) {
            while(l <= r && q[l] < i - m) l++;
            ans = max(ans, sum[i] - sum[q[l]]);
            while(l <= r && sum[q[r]] >= sum[i]) r--;
            q[++r] = i;
        }
    }
    void print(){
        printf("%lld
    ", ans);
    }
    int main(){
        init(); 
        work();
        print();
        return 0;
    }
    View Code

    HLOJ 无穷的序列

    题意:有一个无穷序列如下:110100100010000100000… 请你找出这个无穷序列中指定位置上的数字。

    题解:bitset模板题,对序列用bitset维护。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e7 + 50;
    int n, a[N], maxn = 0, k;
    bitset <100000000> p;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read(), maxn = max(maxn, a[i]);
        for(int i = 1;i <= maxn; i += k, k++) p.set(i);
    }
    void print(){
        rep(i, 1, n) printf("%d
    ", p.test(a[i]));
    }
    int main(){
        init(); 
        print();
        return 0;
    }
    View Code

    HLOJ Largest Rectangle in a Histogram

    题意:这道题让求直方图中最大的矩形(具体略)。

    题解:单调栈模板题,对矩形面积用单调栈维护。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[N], s[N], w[N], p = 0;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        while(~scanf("%d", &n)){
            if(n == 0) break; 
            ll ans = 0;
            rep(i, 1, n) a[i] = read();
            a[n+1] = p = 0;
            rep(i, 1, n+1){
                if(a[i] > s[p]) s[++p] = a[i], w[p] = 1;
                else {
                    int width = 0;
                    while (s[p] > a[i]) {
                        width += w[p];
                        ans = max(ans, (ll)width * s[p]);
                        p--;
                    }
                    s[++p] = a[i], w[p] = width + 1;
                }
            }
            printf("%lld
    ", ans);
        }
    }
    int main(){
        init();
        return 0;
    }
    View Code

    HLOJ Team Queue

    题意:有t个团队的人正在排一个长队。每次新来一个人时,如果他有队友在排队,那么这个新人会插队到最后一个队友的身后。如果没有任何一个队友排队,则他会排到长队的队尾。 输入每个团队中所有队员的编号,要求支持如下3种指令(前两种指令可以穿插进行) 对于每个DEQUEUE指令,输出出队人的编号。

    题解:队列维护序列,按照题意描述操作序列就行了。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e4 + 50;
    int n, m, v[N*N], p, t;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int main(){
        while(~scanf("%d", &n)){
            if(n == 0) break;
            t++; queue <int> q[N];
            printf("Scenario #%d
    ", t);
            rep(i, 1, n){
                m = read();
                rep(j, 1, m) p = read(), v[p] = i;
            }
            char ch[100]; int x;
            while(~scanf("%s", ch)){
                if(ch[0] == 'S') break;
                if(ch[0] == 'E') {
                    x = read();
                    if(q[v[x]].empty()) q[0].push(v[x]);
                    q[v[x]].push(x);
                }
                if(ch[0] == 'D'){
                    printf("%d
    ",q[q[0].front()].front());
                    q[q[0].front()].pop();
                    if(q[q[0].front()].empty()) q[0].pop();
                }
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    HLOJ Raid*

    题意:给定两组点的坐标,求不在同一组内的点的最小距离。

    题解:平面最近点对问题,将同一组内的点的距离赋值为正无穷,分治法求一下平面最近点对即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50, inf = 0x3f3f3f3f;
    struct node{ int x, y, id; } a[N], q[N];
    int n, t;
    double ans; 
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    double dist(node a, node b){ 
        if(a.id == b.id) return 1e9;
        return sqrt(1.0*(a.x-b.x)*(a.x-b.x) + 1.0*(a.y-b.y)*(a.y-b.y));
    }
    double MIN(double a, double b){ return a < b ? a : b;}
    bool mycmp1(node a, node b){ return a.x < b.x; }
    bool mycmp2(node a, node b){ return a.y < b.y; }
    double divide(int l, int r){
        if(l == r) return 1e9;
        int mid = (l+r)>>1, k = 0;
        double ans = MIN(divide(l, mid), divide(mid+1, r));
        rep(i, l, r) if(fabs(a[i].x - a[mid].x) <= ans) q[++k] = a[i];
        sort(q+1, q+k+1, mycmp2);
        rep(i, 1, k) rep(j, i+1, k){
            if(q[j].y - q[i].y <= ans) ans = MIN(ans, dist(q[i], q[j]));
        }    
        return ans;
    }
    int main(){
        t = read();
        while(t --> 0){
            n = read();
            rep(i, 1, (n<<1)){
                a[i].x = read(), a[i].y = read();
                a[i].id = (i <= n)?0:1;
            }
            sort(a+1, a+(n<<1)+1, mycmp1);
            ans = divide(1, (n<<1));
            printf("%.3lf
    ", ans);
        }
        return 0;
    }
    View Code

    HLOJ Snowflake Snow Snowflakes

    题意:您可能听说没有两个雪花是相似的。 你的任务是编写一个程序来确定这是否真的如此。 您的程序将读取有关雪花集合的信息,并搜索可能相同的一对。 每个雪花都有六个手臂。 对于每个雪花,您的程序将提供六个臂中每个臂的长度的测量。 任何具有相同长度相应臂的雪花都应该被程序标记为可能相同。

    题解:在读入一个雪花的时候把这些情况全部放入哈希表中,如果某次插入的时候发生冲突,则说明存在重复的雪花,并且后面的不需要再处理。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e5 + 50;
    int n, tot, mod = 99991, snow[N][6], head[N], next[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    int H(int *a){
        int sum = 0, mul = 1;
        rep(i, 0, 5){
            sum = (sum + a[i]) % mod;
            mul = (ll)mul * a[i] % mod;
        }
        return (sum + mul) % mod;
    }
    bool equal(int *a, int *b){
        rep(i, 0, 5) rep(j, 0, 5){
            bool eq = 1;
            rep(k, 0, 5) if(a[(i+k)%6] != b[(j+k)%6]) eq = 0;
            if(eq) return 1;
            eq = 1;
            rep(k, 0, 5) if(a[(i+k)%6] != b[(j-k+6)%6]) eq = 0;
            if(eq) return 1;
        }
        return 0;
    }
    bool insert(int *a){
        int val = H(a);
        for(int i = head[val];i;i = next[i]){
            if(equal(snow[i], a)) return 1;
        }
        ++tot;
        memcpy(snow[tot], a, 6 * sizeof(int));
        next[tot] = head[val];
        head[val] = tot;
        return 0;
    }
    int main(){
        n = read();
        rep(i, 1, n){
            int a[10];
            rep(j, 0, 5) a[j] = read();
            if(insert(a)){
                puts("Twin snowflakes found.");
                return 0;
            }
        }
        puts("No two snowflakes are alike.");
        return 0;
    }
    View Code

    9月18日

    HLOJ 前缀统计

    题意:给定N个字符串S1,S2...SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。输入字符串的总长度不超过10^6,仅包含小写字母。

    题解:Trie树模板题,对于每个询问,在检索过程中累加途径的每个节点的cnt值,就是该询问的答案。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, m, end[N];
    int trie[N][26], tot = 1;
    char s[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void insert(char* str){
        int len = strlen(str), p = 1;
        rep(k, 0, len-1){
            int ch = str[k] - 'a';
            if(trie[p][ch] == 0) trie[p][ch] = ++tot;
            p = trie[p][ch];
        }
        end[p]++;
    }
    int search(char* str){
        int len = strlen(str), p = 1, res = 0;
        rep(k, 0, len-1){
            int ch = s[k] - 'a';
            if (!trie[p][ch]) break;
            p = trie[p][ch];
            res += end[p];
        }
        return res;
    }
    int main(){
        n = read(); m = read();
        rep(i, 1, n)  scanf("%s", s), insert(s);
        rep(i, 1, m) {
            scanf("%s", s);
            printf("%d
    ", search(s));
        }
        return 0;
    }
    View Code

    HLOJ The XOR Largest Pair

    题意:在给定的N个整数A1,A2……AN中选出两个进行xor运算,得到的结果最大是多少?

    题解:把每个整数看作长度为32的二进制01串(数值较小时在前边补0),并且把A1~Ai-1对应的32位二进制串插入一棵Trie树即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int a[N];
    int trie[N*3][2], tot = 0;
    int n, ans = 0;
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void insert(int x){
        int p = 0;
        per(k, 31, 0){
            int ch = (x>>k) & 1;
            if(!trie[p][ch]) trie[p][ch] = ++tot;
            p = trie[p][ch]; 
        }
    }
    int search(int x){
        int p = 0, res = 0;
        per(k, 31, 0){
            int ch = (x>>k) & 1;
            if(trie[p][ch^1]) p = trie[p][ch^1], res = (res<<1) | 1;
            else p = trie[p][ch], res = (res<<1);
        }
        return res;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read(), insert(a[i]);
        rep(i, 1, n) ans = max(ans, search(a[i]));
    }
    void print(){
        printf("%d
    ", ans);
    }
    int main(){
        init();
        print();
        return 0;
    }
    View Code

     HLOJ 子序列累加和

    题意:现在有N个数的数列。现在你定义一个子序列是数列的连续一部分,子序列的值是这个子序列中最大值和最小值之差。给你这N个数,小x想知道所有子序列的值得累加和是多少

    题解:这道题分治应该可以做,不过要学习的是这道题的单调栈做法,就是求出序列的所有max值之和,再求出所有的min值之和,再相减,用单调栈实现序列中每一个数的贡献。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, a[N], s[N], maxl[N], minl[N], maxr[N], minr[N], k = 0;
    ll ans = 0; 
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read();
    }
    void work(){
        rep(i, 1, n){
            while(k != 0 && a[s[k]] < a[i]){
                maxl[i] += maxl[s[k]] + 1;
                k--; 
            } 
            s[++k] = i;
        }
        k = 0;
        per(i, n, 1){
            while(k != 0 && a[s[k]] <= a[i]){
                maxr[i] += maxr[s[k]] + 1;
                k--; 
            }
            s[++k] = i;
        }
        k = 0;
        rep(i, 1, n){
            while (k != 0 && a[s[k]] > a[i]){
                minl[i] += minl[s[k]] + 1;
                k--;
            }
            s[++k] = i;
        }
        k = 0;
        per(i, n, 1){
            while (k != 0 && a[s[k]] >= a[i]){
                minr[i] += minr[s[k]] + 1;
                k--;
            }
            s[++k] = i;
        }
        rep(i, 1, n)
            ans += ((maxl[i]+1)*(maxr[i]+1) - (minl[i]+1)*(minr[i]+1))*a[i];
    }
    void print(){
        printf("%lld
    ", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    HLOJ holiday

    题意:经过几个月辛勤的工作,FJ决定让奶牛放假。假期可以在1…N天内任意选择一段(需要连续),每一天都有一个享受指数W。但是奶牛的要求非常苛刻,假期不能短于P天,否则奶牛不能得到足够的休息;假期也不能超过Q天,否则奶牛会玩的腻烦。FJ想知道奶牛们能获得的最大享受指数。

    题解:单调队列维护符合条件的序列的单调性。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    ll n, P, Q, a[N], sum[N];
    ll q[N], ans = -1e9;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read(), P = read(), Q = read();
        rep(i, 1, n) a[i] = read();
        rep(i, 1, n) sum[i] = sum[i-1] + a[i];
    }
    void work(){
        int l = 1, r = 0;
        rep(i, P, n){
            while(l <= r && sum[q[r]] >= sum[i-P]) r--;
            q[++r] = i-P;
            while(l <= r && q[l] < i-Q) l++;
            ans = max(ans, sum[i] - sum[q[l]]);
        }
    } 
    void print(){
        printf("%lld
    ", ans);
    }
    int main(){
        init();
        work(); 
        print();
        return 0;
    }
    View Code

    9月19日

    P3132 [USACO16JAN]愤怒的奶牛Angry Cows

    题意:有N个草堆在数轴的不同位置,坐标为x1,x2,….,xn。如果玩家以能量R把奶牛发射到坐标x,就会引爆半径R及以内的的草堆,即坐标范围[x−R,x+R]的草堆都会燃爆,每个被奶牛引爆的草堆又会2次引爆半径R-1及以内的的草堆,2次引爆的草堆又会3次引爆半径R-2及以内的的草堆...直到一次引爆后没有其他草堆被波及或半径为0。

    现在只有1头奶牛,能量为R,请计算如果要引爆所有的草堆,最小的R是多少?

    题解:用f[i]记录以i为以i为圆心可以向左覆盖前i-1个点的最小半径。 再用g[i]记录以i为圆心可以向右覆盖至第n个点的最小半径,二分答案即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a);i <= (b);i++)
    #define per(i, a, b) for(int i = (a);i >= (b);i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    double eps = 0.001;
    double a[N], s[N], maxx = 0, pos, posl, posr;
    double vis[N], f[N], g[N];
    double ans;
    int n;
    inline ll read(){
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9'){x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read();
        sort(a+1, a+n+1);
        rep(i, 2, n) s[i] = a[i] - a[i-1];
        f[1] = g[n] = 0;
           rep(i, 2, n){
            f[i] = 1e9;
            int l = 1, r = i;
            while(l + 1 < r){
                int mid = (l+r)/2;
                if(f[mid-1] + 1 < a[i]-a[mid-1]) l = mid;
                else r = mid;
            }
            f[i] = min(max(a[i]-a[l-1], f[l-1] + 1), max(a[i] - a[r-1], f[r-1] + 1));
        }
        per(i, n-1, 1){
            g[i] = 1e9;
            int l = i, r = n - 1;
            while(l + 1 < r){
                int mid = (l+r)/2;
                if(g[mid+1] + 1 < a[mid+1] - a[i]) r = mid;
                else l = mid;
            }
            g[i] = min(max(a[l+1] - a[i], g[l+1] + 1), max(a[r+1] - a[i], g[r+1] + 1));
        }
    }
    bool check(double x){ 
        per(i, n, 1){
            if(f[i] + 1 <= x){
                for(int j = i;j <= n && a[j] <= a[i] + 2.0*x; j++)
                    if(g[j] + 1 <= x) return true;
                break;
            }
        }
        return false;
    }
    void work(){
        double l = 1.0, r = a[n]*1.0;
        while(eps < r-l){
            double mid = (l+r) / 2;
            if(check(mid)) r = mid;
            else l = mid;
        }
        ans = l;
    }
    void print(){
        printf("%.1lf", ans);
    }
    int main(){
        init();
        work();
        print();
        return 0;
    }
    View Code

    9月23日

    HLOJ Dropping Test

    题意:给定你n组ai,bi,让你取出n−k组,使得这nk组的a之和除以b之和最大.

    题解:01分数规划模板题,设答案为x, 则 a[i] - b[i] * x 的前n-k组的累加和必须大于等于0。二分答案即可。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const double eps = 1e-9;
    const int N = 1e6 + 50;
    int n, k;
    double a[N], b[N], v[N];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    bool mycmp(double x, double y) {return x > y; }
    bool check(double x){
        double res = 0;
        rep(i, 1, n) v[i] = a[i] - b[i] * x;
        sort(v+1, v+n+1, mycmp); 
        rep(i, 1, n-k) res += v[i];
        return res >= 0;
    }
    void init(){
        while(~scanf("%d%d", &n, &k)) {
            if(n == 0) break;
            double l = 0, r = 0;
            rep(i, 1, n) scanf("%lf", &a[i]), r += a[i];
            rep(i, 1, n) scanf("%lf", &b[i]);
            while(r-l > eps){
                double mid = (l+r) / 2;
                if(check(mid)) l = mid;
                else r = mid;
            }
            printf("%.0lf
    ", l * 100);    
        }
    }
    int main(){
        init();
        return 0;
    }
    View Code

    9月24日

    HLOJ 花店橱窗

    题意:https://www.luogu.org/problem/P1854 

    题解:一道比较显然的DP,设F(i,j)表示到(i,j)位置的最优值,状态转移也非常显然,不再叙述,主要是输出方案值得学习,看代码理解。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    int n, m, a[2010][2010], f[2010][2010];
    int ans = -1e9, k[N]; 
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init() {
        n = read(); m = read();
        rep(i, 1, n) rep(j, 1, m) a[i][j] = read(), f[i][j] = -1e9;
    }
    void find(int x, int y){
        if(x <= 0) return ;
        int p = x;
        while(f[x][p] != y) p++;
        k[x] = p;
        find(x-1, y-a[x][p]);
        return ;
    }
    void work() {
        rep(i, 1, n) rep(j, 1, m) rep(k, i-1, j-1){
            f[i][j] = max(f[i][j], f[i-1][k] + a[i][j]);
        }
        rep(i, n, m) ans = max(ans, f[n][i]);
        printf("%d
    ", ans);
        find(n, ans);
        rep(i, 1, n) printf("%d ", k[i]);
        printf("
    ");
    }
    int main(){
        init();
        work();
        return 0;
    }
    View Code

     hnoi2010 合唱队

    题意:给定一串序列,问有多少种初始序列经过如题操作可以得到此序列。

    题解:f[i][j][1]为可以排成理想队列中[i,j][区间,且以最后一个排进去是第i人的初始队列种数。

    f[i][j][0]为可以排成理想队列中[i,j]区间,且以最后一个排进去是第j人的初始队列种数。

    限于篇幅,状态转移部分看代码理解。

    #include<bits/stdc++.h>
    
    #define ll long long
    #define mp make_pair
    #define rep(i, a, b) for(int i = (a); i <= (b); i++)
    #define per(i, a, b) for(int i = (a); i >= (b); i--)
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef double db;
    const int N = 1e6 + 50;
    const int mod = 19650827;
    int n, a[N], f[1010][1010][2];
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
        while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
        return x*f;
    }
    void init(){
        n = read();
        rep(i, 1, n) a[i] = read();
        rep(i, 1, n) f[i][i][1] = 1;
        per(l, n, 1) rep(r, l+1, n) {
            f[l][r][0] = (f[l][r][0] + f[l+1][r][0] * (a[l] < a[l+1]))%mod;
            f[l][r][0] = (f[l][r][0] + f[l+1][r][1] * (a[l] < a[r]))%mod; 
            f[l][r][1] = (f[l][r][1] + f[l][r-1][0] * (a[r] > a[l]))%mod;
            f[l][r][1] = (f[l][r][1] + f[l][r-1][1] * (a[r] > a[r-1]))%mod;
        }
        printf("%d
    ", (f[1][n][1] + f[1][n][0])%mod);
    }
    int main(){
        init();
        return 0;
    }
    View Code
  • 相关阅读:
    C# 实现 Snowflake算法生成唯一性Id
    kafka可视化客户端工具(Kafka Tool)的基本使用(转)
    docker 安装kafka
    Model类代码生成器
    使用docker 部署rabbitmq 镜像
    Vue 增删改查 demo
    git 提交代码到库
    Android ble蓝牙问题
    mac 配置 ssh 到git (Could not resolve hostname github.com, Failed to connect to github.com port 443 Operation timed out)
    okhttp
  • 原文地址:https://www.cnblogs.com/smilke/p/11523009.html
Copyright © 2011-2022 走看看