zoukankan      html  css  js  c++  java
  • 测试1T1

    题目描述

    Lyk得到了一个1~n的全排列。Txm每次会交换第i个数和第j个数,对于每次交换,lyk需要回答该全排列的逆序对数为多少。
    “1、2、3、4......248289469!”lyk如是回答道。
    “最后答案取模2......”

    输入

    第一行一个数,n
    第二行为1~n的某个全排列
    第三行一个数m,表示交换操作的次数。
    接下来m行,每行两个数i和j

    输出

    M行,表示m次交换后的答案。

    样例输入

    4
    1 2 3 4
    1
    1 2
    

    样例输出

    1

    提示

    Constraints

    对于30%,n,m<=1000

    对于100%,n,m<=100000

    第一次做果断被坑
    归并+暴力线扫忘了a[i]>a[j]时的ans--
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int a[100005],b[100005],A[100005];
    long long ans;
    void merge(int l,int mid,int r)
    {
        int i=l;int j=mid+1;int k=l;
        while(i<=mid&&j<=r)
        {
            if(a[i]<=a[j])
            b[k++]=a[i++];else ans+=mid-i+1,b[k++]=a[j++];
        }
        for (int p=i;p<=mid;p++)
        b[k++]=a[p];
        for (int p=j;p<=r;p++)
        b[k++]=a[p];
        for(int p=l;p<=r;p++)
        a[p]=b[p];
    }
    void merge_sort(int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)/2;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        merge(l,mid,r);
    }
    
    int main()
    {
        freopen("lyk.in","r",stdin);
        freopen("lyk.out","w",stdout);
        int n,m;
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
          A[i]=a[i];  
        merge_sort(1,n);  
        scanf("%d",&m);
        int x,y;
        long long ANS=ans;
        for(int i=1;i<=m;i++)
        {
            //ans=ANS;
            scanf("%d %d",&x,&y);
            if(x>y) swap(x,y);
            for(int k=x+1;k<=y-1;k++)
            {
                if(A[k]>A[x])ans++;else ans--;
                if(A[k]>A[y])ans--;else ans++;
            }
            if(A[x]<A[y]) ans++;
                    //忘了else ans--;
            swap(A[x],A[y]);
            printf("%lld
    ",ans%2);
        }
        return 0;
    }

    正解:

    每次交换a[i]和a[j]时会对a[i+1..j-1]中的数询问,加上比a[i]大的,减去比a[i]小的;加上比a[j]小的,减去比a[j]大的;最后考虑a[i]和a[j]的大小关系

    设分别有z,z1个,则有

    ans+=z-(j-i+1-z)+z1-(j-i+1-z1);等价于ans+=2*z+2*z-1-2*(j-i+1)

    因为最后询问ans%2 所以改变ans的只有最后一步(考虑a[i]和a[j]的关系)

    最后判断i是否等于j

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int a[100005],b[100005],A[100005];
    long long ans;
    void merge(int l,int mid,int r)
    {
        int i=l;int j=mid+1;int k=l;
        while(i<=mid&&j<=r)
        {
            if(a[i]<=a[j])
            b[k++]=a[i++];else ans+=mid-i+1,b[k++]=a[j++];
        }
        for (int p=i;p<=mid;p++)
        b[k++]=a[p];
        for (int p=j;p<=r;p++)
        b[k++]=a[p];
        for(int p=l;p<=r;p++)
        a[p]=b[p];
    }
    void merge_sort(int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)/2;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        merge(l,mid,r);
    }
    
    int main()
    {
        //freopen("lyk.in","r",stdin);
        //freopen("lyk.out","w",stdout);
        int n,m;
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
          A[i]=a[i];  
        merge_sort(1,n);  
        ans%=2; 
        scanf("%d",&m);
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            if(x!=y)
            ans=1^ans;
            printf("%lld
    ",ans);    
        } 
        return 0;
    }

    还被cout坑了

     

  • 相关阅读:
    JS 日期加多少天,减多少天
    SQL 触发器
    SGU100
    连续子数组的最大和
    字符串的排列
    二叉搜索树与双向链表
    数组中出现次数超过一半的数字
    复杂链表的复制
    二叉树中和为某一值的路径
    二叉搜索树的后序遍历序列
  • 原文地址:https://www.cnblogs.com/dancer16/p/6840637.html
Copyright © 2011-2022 走看看