CSP模拟6

保龄力,好开心

头一次考试,直接保龄,哎,还是太菜了。

 

A. 排序

题目链接

考试时有思路,但是没有写下去,挺可惜的。

首先让我们求逆序对的个数,n<=1000,直接 O(n2) 求就行.

然后思考如何换,他要求我们换且必须换m次。这时想到,如何每一次交换,只是改变一对相对大小关系,不就行了。

后来发现不可行,通过只交换一次就达到目的不太可能,因为只交换一次只能保证一对相对关系;

而且如果改变一个逆序对,很难保证之前的逆序对还是逆序对。

那交换多次不就行了!

所以我们设 pos[i] 表示数值 i 在 a 排列中的位置(因为是排列,所以不用考虑重复),即 pos[a[i]]=i ;

然后进行交换 , 交换然后排序,这让我们不禁想到了冒泡排序,每一次内循环把当前数列最大值放到最后一位。

在这里可以用到类似的思想,依次进行操作 (pos[a[n]+1],n),(pos[a[n]+2],n) ........(pos[n],n)

这样我们发现最后的排列 b, 不仅把 n 放到了最后一位,还使之前的相对大小关系不变,而且把包含 n 的逆序对都用了。(可以认为把比a[n]大的数都砍了一,然后把n放在了最后,仔细想一下就可以了)

重复以上的操作,就会得到单调递增的数列。

/*#include <iostream>
#include <cstdio>
#include <vector> 
#include <algorithm>*/

#include <bits/stdc++.h> 

const int MAXN=1010;

using namespace std;

int n,m,tot;
int a[MAXN],pos[MAXN],mp[MAXN];

struct node {
    int x,y;
};

vector<node> 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*10+ch-48;
        ch=getchar();
    }
    return x*f;
}

void swp(int x,int y){
    pos[a[x]]=y;
    pos[a[y]]=x;
    swap(a[x],a[y]);
    ans.push_back((node){x,y});
}
int main() {
    
    n=read();
    
    for(int i=1;i<=n;i++) {
        a[i]=read();
        mp[i]=a[i];
    }
    sort(mp+1,mp+n+1);
    int len=unique(mp+1,mp+n+1)-mp-1;
    for(int i=1;i<=n;i++) {
        a[i]=lower_bound(mp+1,mp+len+1,a[i])-mp;
        pos[a[i]]=i;
    }
    
    for(int i=1;i<=n;i++) {
        for(int j=1;j<i;j++) {
            if(a[j]>a[i]) {
                m++;
            }
        }
    }
    
    printf("%d\n",m);
    
    for(int i=n;i>=1;i--) {
        for(int j=a[i]+1;j<=i;j++) {
            swp(pos[j],i);
        }
    }
    
    for(int i=0;i<ans.size();i++) {
        printf("%d %d\n",ans[i].x,ans[i].y);
    }
    
    return 0;
}
View Code

 

B. Xorum

题目链接

emmmmm没有思路。

好像可以用神奇的性质做,但是正确性。。。

想要得到“1”,可以把 x 上其他位全部删掉,不就剩下 1 了吗;

至于怎么删掉,设当前 x 共有 a 位;

然后:

设y=x<<(a-1);    设z=x^y;设n=z+y;

设p=y+y;        设m=n^p;    设q=m^x;

手模一下就可以;

此时的q就是1<<(a+1);

再左移,和y进行异或,把y除了 a位的1 的其他位上的数消掉;

得到新y, 再x^新y,,就可以把x最高位的1消掉了;

 

#include <iostream>
#include <cstdio>
#include <vector> 

const int MAXN=100010;

using namespace std;

long long x,tot;

struct node {
    long long x,y;
};
char op[MAXN];

vector <node> ans;

/*inline int read() {
    long long f=1,x=0; char ch=getchar();
    while(ch<'0' && ch>'9') {
        if(ch=='-') {
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0' && ch<='9') {
        x=x*10+ch-'0';
        ch=getchar(); 
    }
    return x*f;
}*/

long long work(long long x) {
    long long now=(x>>1),y=x;
    while(now) {
        
        ans.push_back((node){y,y});
        op[tot++]='1';
        y<<=1,now>>=1;
    }
    long long z=x^y; ans.push_back((node){x,y}) , op[tot++]='2';
    long long n=z+y; ans.push_back((node){z,y}) , op[tot++]='1';
    long long p=y+y; ans.push_back((node){y,y}) , op[tot++]='1';
    long long m=n^p; ans.push_back((node){n,p}) , op[tot++]='2';
    long long q=m^x; ans.push_back((node){m,x}) , op[tot++]='2';
    
    while(y!=(y&-y)) {
        if(y&q) {
            ans.push_back((node){y,q}); y^=q;
            op[tot++]='2';
        }
        ans.push_back((node){q,q});
        op[tot++]='1';
        q<<=1;
    }
    ans.push_back((node){x,y}) , op[tot++]='2';
    return x^y;
}

int main() {
    
    scanf("%lld",&x);
    
    while(x!=1) {
        x=work(x);
    }
    
    printf("%lld\n",tot);
    
    for(int i=0;i<tot;i++) {
        if(op[i]=='1') {
            printf("1 %lld %lld\n",ans[i].x,ans[i].y);
        }
        if(op[i]=='2') {
            printf("2 %lld %lld\n",ans[i].x,ans[i].y);
        }
    }
    
    return 0;
} 
View Code

 

posted @ 2023-07-26 17:41  Trmp  阅读(21)  评论(0)    收藏  举报
-->