• 17.8.12第六次测试


    1.ksum

    【问题描述】
    Peter喜欢玩数组。NOIP这天,他从Jason手里得到了大小为n的一个正整数
    数组。
    Peter求出了这个数组的所有子段和,并将这n(n+1)/2个数降序排序,他想
    知道前k个数是什么。
    【输入格式】
    输入文件名为 ksum.in。
    输入数据的第一行包含两个整数 n 和 k。
    接下来一行包含 n 个正整数,代表数组。
    【输出格式】
    输出文件名为 ksum.out。
    输出 k 个数,代表降序之后的前 k 个数,用空格隔开。
    【输入输出样例】
    ksum.in 
    3 4
    1 3 4
    ksum.out
    8 7 4 4
    
    ksum.in 
    3 3
    10 2 7
    ksum.out
    19 12 10
    
    【数据规模与约定】
    对于所有数据,满足 ai≤10
    9 k≤n(n+1)/2,n≤100000,k≤100000
    测试点编号 n ≤           k ≤
    1              100          5000
    2              500          100000
    3              1000        80000
    4              1000        100000
    5              10000      50000
    6              20000      80000
    7              50000      80000
    8              100000    80000
    9              100000    100000
    10            100000    100000
    View Code

    题解:算是个模拟题吧。最大字段肯定是整个数列。进行如下操作:取出当前最大子段,然后放入这个子段的左端-1和其右端-1两个字段(这两段肯定是它之内比它小的最大子段了)重复直到结束。脑补一下就可以出来,或者手推。这里用到一个叫set的东西非常好,因为可能从两个子段同时得到同一个小子段,所以会有重复情况,为了避免这个情况,set就行。set集合其实就相当于自动去重的优先队列,自动避免了上述情况。更多set的东西可以百度。对了,结构体用set需要用重载运算符重载"<"。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    using namespace std;
    #define ll long long
    struct num{
        ll l,r,val;
        bool operator<(const num &b)const{
            num a=*this;
            if(a.val!=b.val) return a.val<b.val;
            if(a.l != b.l) return a.l < b.l;
            return a.r < b.r;
        }
    }e[1000100];
    set<num>q;
    long long a[100010],sum,cnt;
    int n,k,t;
    int main(){
        freopen("ksum.in","r",stdin);
        freopen("ksum.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
            sum+=a[i];
        }
        e[++cnt].l=1;
        e[cnt].r=n;
        e[cnt].val=sum;
        q.insert(e[1]);
        while(k--){
            num x=*q.rbegin();q.erase(x);
            printf("%I64d ",x.val);
            if(x.l<x.r){
                e[++cnt].l=x.l+1;
                e[cnt].r=x.r;
                e[cnt].val=x.val-a[x.l];
                q.insert(e[cnt]);
                e[++cnt].l=x.l;
                e[cnt].r=x.r-1;
                e[cnt].val=x.val-a[x.r];
                q.insert(e[cnt]); 
            }
        }
        return 0;    
    }
    View Code

    2.奇袭

    【问题描述】
    由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上
    要迎来最终的压力测试——魔界入侵。
    唯一一个神一般存在的Administrator被消灭了,靠原本的整合骑士的力量
    是远远不够的。所以爱丽丝动员了UW全体人民,与整合骑士一起抗击魔族。
    在UW的驻地可以隐约看见魔族军队的大本营。整合骑士们打算在魔族入侵
    前发动一次奇袭,袭击魔族大本营!
    为了降低风险,爱丽丝找到了你,一名优秀斥候,希望你能在奇袭前对魔
    族大本营进行侦查,并计算出袭击的难度。
    经过侦查,你绘制出了魔族大本营的地图,然后发现,魔族大本营是一个N
    ×N的网格图,一共有N支军队驻扎在一些网格中(不会有两只军队驻扎在一起)。
    在大本营中,每有一个k×k(1≤k≤N)的子网格图包含恰好k支军队,我们
    袭击的难度就会增加1点。
    现在请你根据绘制出的地图,告诉爱丽丝这次的袭击行动难度有多大。
    【输入格式】
    第一行,一个正整数N,表示网格图的大小以及军队数量。
    接下来N行,每行两个整数,Xi,Yi,表示第i支军队的坐标。
    保证每一行和每一列都恰有一只军队,即每一个Xi和每一个Yi都是不一样
    的。
    【输出格式】
    一行,一个整数表示袭击的难度。
    【输入输出样例】
    raid.in 
    5
    1 1
    3 2
    2 4
    5 5
    4 3
    
    raid.out
    10
    【样例解释】
    显然,分别以(2,2)和(4,4)为左上,右下顶点的一个子网格图中有3支军队,
    这为我们的难度贡献了1点。
    类似的子网格图在原图中能找出10个。
    【数据范围】
    对于30%的数据,N ≤ 100
    对于60%的数据,N ≤ 5000
    对于100%的数据,N ≤ 50000
    View Code

    题解:二维压一维后,题目可化简为:给定 N 个数的一个排列,问这个序列中有多少个子区间的数恰好是连续的。这个画图可得。

    进一步可以化为:有多少种情况使得,相邻的 k 个数中最大值和最小值的差小于等于 k-1。

    大致有两种解法,一种是分治,一种是线段树。
    这里主要讲一下分治的解法。
    考虑分治,对于当前分治区间[L,R],记区间中点为 mid。当
    前区间的答案就是Ans[L..mid]+Ans[mid+1..R]+跨过中点的合
    法区间数,然后就分为两种情况了:
    1.最小值和最大值在同侧。
    2.最小值和最大值在异侧。
    下面只考虑最值同在左,和最小值在左,最大值在右的情况。
    其余两种是对称的。
    对于最值同在左侧的情况,我们枚举左边界在哪,然后可以计算出右边界的位置,在判断是否合法,统计答案。

    时间复杂度:
    O(N).对于最小值在左侧,最大值在右侧的情况,如果一个区间满足我们所要求的关系的话话,就一定有: max(a[mid 1]...a[right])  min(a[left]...a[mid]) = right -left

    移项可得

    max(a[mid 1]...a[right]) -right = min(a[left]..a[mid])-left然后可以用单调栈+桶来完成这个任务。时间复杂度:O(N). 如果加一些黑科技可以大大减少代码量,但是复杂度会多一 个 log。 总的时间复杂度:O(NlogN)/O(NlogN^2) 简单提一下,线段树解法的思路大致也是维护一个单调栈, 然后进行区间修改和查询,统计答案。 时间复杂度:O(NlogN).

    代码:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std ;
    
    #define N 600000 + 10
    typedef long long ll ;
    int TAX[N] ;
    int A[N] ,lmax[N] , lmin[N] , rmax[N] , rmin[N] ,a,b;
    int *tax = TAX + 300005 ;
    int n ;
    
    ll cal(int l,int r,int m){
        ll ret=0;
        lmax[m]=lmin[m]=A[m];
        rmax[m+1]=rmin[m+1]=A[m+1];
        for(int i=m-1;i>=l;i--){
            lmax[i] = max( lmax[i+1] , A[i] ) ;
            lmin[i] = min( lmin[i+1] , A[i] ) ;
        }
        for(int i=m+2;i<=r;i++){
            rmax[i] = max( rmax[i-1] , A[i] ) ;
            rmin[i] = min( rmin[i-1] , A[i] ) ;
        }
        for(int i=l;i<=m;i++){
            int j=lmax[i]-lmin[i]+i;
            if(rmax[j]<lmax[i]&&rmin[j]>lmin[i]&&j>m){
                ret++;
            }
        }
        int p=m+1,q=m;
        while(q<r&&rmin[q+1]>lmin[l])q++,tax[rmax[q]-q]++;
        while(p<=r&&rmax[p]<lmax[l])tax[rmax[p]-p]--,p++;
        for(int i=l;i<=m;i++){
            while(p>m+1&&rmax[p-1]>lmax[i])p--,tax[rmax[p]-p]++;
            while(q>m&&rmin[q]<lmin[i])tax[rmax[q]-q]--,q--;
            ret+=max(tax[lmin[i]-i],0);
        }
        for (int i = m + 1 ; i <= r ; i ++ ) tax[rmax[i]-i] = 0 ;
        return ret;
    }
    
    ll solve(int l,int r){
        if(l==r)return 1ll;
        int m=(l+r)>>1;
        ll ret=0;
        ret+=solve(l,m);
        ret+=solve(m+1,r);
        ret+=cal(l,r,m);
        reverse (A+l,A+r+1);
        if((r-l+1)%2)m--;
        ret+=cal(l,r,m);
        reverse(A+l,A+r+1);
        return ret;
    }
    
    int main(){
        freopen( "raid.in" , "r" , stdin ) ;
        freopen( "raid.out" , "w" , stdout ) ;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a,&b);
            A[a]=b;
        }
        printf("%I64d
    ",solve(1,n));
        return 0;
    } 
    View Code

    3.十五数码

    【题目描述】
    给出起始顺序,要求通过 0 的移动(与上下左右交换),排成以下顺序:
    1 2 3 4
    5 6 7 8
    9 10 11 12
    13 14 15 0
    【输入格式】
    从文件 fiften.in 中读入数据,四个数一行,共四行。
    【输出格式】
    输出到文件 fifteen.out 中。
    输出最少移动次数。如果无解输出 No。
    【样例 1 输入】
    1 2 3 4
    5 6 7 8
    9 10 11 12
    13 14 0 15
    【样例 1 输出】
    1
    【样例 2 输入】
    1 11 3 8
    5 7 0 2
    9 13 4 12
    6 10 14 15
    【样例 2 输出】
    33
    【数据范围】
    对于 20%的数据,保证有解并且 Ans <= 12;
    对于 50%的数据,保证有解并且 Ans <= 28;
    存在 10%的数据无解。
    对于 100%的数据,如果有解,Ans <= 50;
    View Code

    题解:丧病的八数码的升级版。然而当时我连八数码都不会打。orz。

    就是搜,使劲搜。IdA*算法的搜。

    这题时限相当坑,两个点死活过不去,最后加长到三秒了才过orz。

    这题的check函数判断无解,就是数列转换为一维后,如果包含0在内计算每一个数之前小于自己的数(含0)的个数之和加上0当前位置到其应在位置的曼哈顿距离为奇数则有解,反之无解。

    剩下就是搜索,界限bound为搜索深度,每次更新为大于当前值最小的(step+h)step为当前步数,h是估价函数。

    h是当前每个数到其应在位置的曼哈顿距离和。(不含0)

    差不多就这些。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    char str[10];
    int xx[17],yy[17],bound,flg;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    char s[4] ={'l','r','u','d'};
    int mm,xq,yq,r;
    inline int caldis(int aa,int x,int y)
    {
        return abs(xx[aa]-x) + abs(yy[aa]-y);
    }
    
    struct node
    {
        int pos,mat[20];
        char out[100];
        int H()
        {
            register int ret = 0;
            for(register int i = 0; i < 15; i ++)
                ret += abs(xx[mat[i]] - (i>>2)) + abs(yy[mat[i]] - (i&3));
            return ret;
        }
        bool check()
        {
            int tot = 0;
            
            for(int i = 0; i < 16; i ++){
                if(!mat[i]) continue;
                for(int j = 0; j < i; j ++)
                    if(mat[j] < mat[i]) tot++;
            }
            tot+=mm;
            if(!(tot&1)) return false;
            else return true;
        }
        void output()
        {
            int len =strlen(out);
            for(int i = len-1; i >=0; i  --)
                putchar(out[i]);
        }
    }a;
    
    bool valid(int x,int y)
    {
        return 0 <= x && x <= 3 && 0 <= y && y <= 3;
    }
    
    bool ok(int aa,int bb)
    {
        if(aa > bb) swap (aa,bb);
        if(aa==0&&bb==1) return false;
        if(aa==2&&bb==3) return false;
        return true;
    }
    
    int dfs(register int step,register int h,register int las)
    {
        if(step + h > bound) return step + h;
        if(!h)
        {
            flg=1;
            return step;
        }
        register int pos =a.pos;
        int x = (a.pos>>2),y = (a.pos&3),ret =127;
        for(int k = 0; k < 4; k ++)
        {
            int tx = x + dx[k];
            int ty = y + dy[k];
            if(!valid(tx,ty)||!ok(k,las)) continue;
            int tar = (tx<<2) + ty;
            swap(a.mat[pos],a.mat[tar]);
            a.pos = tar;
            int ht = h - caldis(a.mat[pos],tx,ty) + caldis(a.mat[pos],x,y);
            int tmp = dfs(step+1,ht,k) ;
            if(flg) return tmp;if(ret>tmp)ret = tmp;
            swap(a.mat[pos],a.mat[tar]);
            a.pos = pos;
        }
        return ret;
    }
    
    int main()
    freopen("fifteen.in","r",stdin);
    freopen("fifteen.out","w",stdout);
    {
        for(int i = 0; i < 16; ++i){
            scanf("%d",&r);
            if(r==0) {
                a.pos = i;
                xq = (i>>2); yq = (i&3);
                mm=3-xq+3-yq;
            }
            else
            {
    
                a.mat[i] = r;
                xx[r] = (i>>2); yy[r] = (i&3);
            }
        }
        if(!a.check()) 
        {
            printf("No
    ");
            return 0;
        }
        for(int i = 0; i < 15; ++i) a.mat[i] = i + 1; a.mat[15] = 0;
        a.pos = 15;
        for(bound = a.H(); bound <= 55&&!flg ; bound = dfs(0,a.H(),4) );
        if(!flg)
        {
                printf("No
    ");
            return 0;
        }
        printf("%d",bound);
    }
    View Code
  • 相关阅读:
    Android系统介绍与框架(转)
    6个值得推荐的Android开源框架简介(转)
    程序员最喜爱的12个Android应用开发框架二(转)
    android在代码中四种设置控件(以及TextView的文字颜色)背景颜色的方法
    Android数据缓存(转)
    [UI]实用案例--Shape绘制实用圆圈
    接口API测试和返回值JSON解析的插件
    Android LayoutInflater详解(转)
    一个json字符串
    Android中设定EditText的输入长度(转)
  • 原文地址:https://www.cnblogs.com/Requiescat/p/7397706.html
Copyright © 2020-2023  润新知