首页 > 其他分享 >CSP6

CSP6

时间:2023-07-26 19:56:04浏览次数:30  
标签:输出 ch 下标 CSP6 样例 int 逆序

T1

题目描述
给出一个长为的排列,请你把它排序。排序方法是:定义一种操作表示交换,先找到所有逆序对满足,任意排成一个排列,使得按照这个顺序操作以后是单调递增的。如果有多种排列,输出任意一种。

输入格式
第一行输入,第二行输入数组。保证是排列。

输出格式
如果不存在答案,输出。

否则,第一行输出表示逆序对数量,接下来行每行输出两个数,表示一次操作,需要满足(是没有经过操作的数组)。

样例
样例输入1
3
3 1 2
样例输出1
2
1 3
1 2

设 \(b[i]\) 意思为 \(i\) 位置应该放的数应该放数是 \(b[i]\) 的数

image

\(b[1]\) 表示第 \(1\) 个位置应该放的数在原数列里的下标是 \(2\)

\(b[2]\) 表示第 \(2\) 个位置应该放的数在原数列里的下标是 \(3\)

\(b[3]\) 表示第 \(3\) 个位置应该放的数在原数列里的下标是 \(1\)

怎么用冒泡排序做这道题呢?

冒泡排序都是比较相邻的两个元素,所以我们将这道题构造成比较不相邻的逆序对

\(b[i]\) 的最终状态是升序排列的,这样就能第 \(i\) 个位置应该放的数是 \(b[i]\)(即为 \(i\))

\(b[i]\) 有几个性质

1.当交换 \(a[b[u]]\) 和 \(a[b[y]]\) 的时候, \(b[u]\) 和 \(b[y]\) 也会交换

假设想让 \(a\) 升序排列,交换 \(a[1]\) 和 \(a[3]\),那么 \(b[2]\) 和 \(b[3]\) 也会交换

image

2.如果 \(b[u]>b[y]\) 且 \(u<y\) 那么\(a[b[u]]\) 和 \(a[b[y]]\) 互为逆序对

\(b[2]\) 和 \(b[3]\) 为例子

\(b[2]=3\) 说明2位置(2)应该放一个下标比较大的数,但是3位置(3)要放一个下标比较小的数,这样就满足了逆序对的定义,即下标较小的位置反而大

这样的话我们求出 \(b[i]\) 数组:\(b[a[i]]=i\) 然后对 \(b\) 冒泡排序成有序,就能求出交换的是那些下标

而且因为交换 \(b\) 中的逆序对对应 \(a\) 中的逆序对,所以将 \(b\) 排到升序,\(a\) 也意味着排到升序,而且不会对其他逆序对造成影响,因为交换的是 \((b[i],b[i+1])\)

同时冒泡排序保证了交换的次数就等于逆序对的个数

image

nt代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Testify{
    inline int read(){
        int f(1),x(0);
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
        return f*x;
    }
    inline void Write(int x){
        if(x>9) Write(x/10);
        putchar(x%10+48);
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        Write(x);
        putchar(' ');
    }
}
using namespace Testify;
const int N=1005;
int n,a[N],Tempestissimo,b[N],c[N];
int op[N],cnt(0);

signed main(void){
    n=read();
    for(register int i=1;i<=n;i++){
        a[i]=b[i]=read();
        // c[i]=i;
    }
    sort(b+1,b+n+1);
    int cnt=unique(b+1,b+n+1)-b-1;
    for(register int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
    }
    for(register int i=1;i<=n;i++){
        b[a[i]]=i;
    }
    for(register int i=1;i<=n;i++){
        for(register int j=i+1;j<=n;j++){
            if(a[i]>a[j]){
                Tempestissimo++;
            }
        }
    }
    Write(Tempestissimo),puts("");
    if(!Tempestissimo) return 0;

    for(register int i=1;i<n;i++){
        for(register int j=1;j<n;j++){
            if(b[j+1]<b[j]){
                printf("%lld %lld\n",b[j+1],b[j]);
                // swap(a[i+1],a[i]);
                swap(b[j+1],b[j]);
            }
        }
    }
    // for(register int i=1;i<=n;i++){
    //     cerr<<a[i]<<" ";
    // }
    return 0;
}

二.B. Xorum

题目描述
你有一块黑板,只写着一个奇数。你可以往黑板上写数,目标是写下1。你可以使用两种操作:选择两个已经写在黑板上的数,写下它们的和或异或和。要求写数字不超过 次且上的数字不超过 。

输入格式
一个奇数。

输出格式
第一行输出操作数,接下来每行输出一个操作,表示写下,表示写下。

样例
样例输入1
3
样例输出1
5
1 3 3
2 3 6
1 3 5
1 3 6
2 8 9
样例输入2
123
样例输出2
10
1 123 123
2 123 246
1 141 123
1 246 123
2 264 369
1 121 246
2 367 369
1 30 30
1 60 60
2 120 121

使用按位计算

因为给定 \(x\) 是奇数,所以他可以表示为 \(1???????????1\)

\[y=1???????????100000000 \]

\[z=x\oplus y=1???????????0???????????1 \]

\[c=z+y=1???????????01???????????1 \]

\[d=c\oplus x=1???????????0000000000 \]

\[e=y<<1=1???????????10000000000000 \]

\[f=d\oplus e=10 000000000000000 \]

然后根据 \(x\) \(y\) \(f\) 解出1

将\(y\)不断左移和\(x\)做异或运算将y化简到 \(100000000000000\)

然后在和 \(x\) 异或将最靠前的1消去,不断循环这个过程就能得到1

代码

点击抄袭代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace Testify{
    inline int read(){
        int f(1),x(0);
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
        return f*x;
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+48);
    }
}
using namespace Testify;
int n;
int x,y,z,c,d,e,f,h;

int sum;
inline int popcount(int s){
    int res=0;
    while(s){
        res++;
        s-=(s&(-s));
    }
    return res;
}
inline int geth(int s){
    int res=0;
    while(s){
        res++;
        s>>=1;
    }
    return res;
}
inline int POP(int s,int t){
    return (s>>t)&1;
}
int cnt(0);
struct node{
    int opt,a,b;
}ans[100005];
signed main(void){  
    // cerr<<POP(4,2);
    x=read();
    while(x!=1){
        y=x;
        h=geth(x);
        for(register int i=1;i<h;i++){
            // printf("1 %lld %lld\n",y,y);
            ans[++cnt]=node{1,y,y};
            y<<=1;
        }
        // printf("2 %lld %lld\n",x,y);
        ans[++cnt]=node{2,x,y};
        z=(x^y);
        ans[++cnt]=node{1,z,y};
        // printf("1 %lld %lld\n",z,y);
        c=(z+y);
        ans[++cnt]=node{2,c,x};
        // printf("2 %lld %lld\n",c,x);
        d=(c^x);
        ans[++cnt]=node{1,y,y};
        // printf("1 %lld %lld\n",y,y);
        e=(y<<1);
        ans[++cnt]=node{2,d,e};
        // printf("2 %lld %lld\n",d,e);
        f=(d^e);
        int op=popcount(x);

        for(register int i=1;i<op;i++){
            while(!POP(y,h++)){
                ans[++cnt]=node{1,f,f};
                // printf("1 %lld %lld\n",f,f);
                f<<=1;
            }
            ans[++cnt]=node{2,y,f};
            // printf("2 %lld %lld\n",y,f);
            y^=f;
            ans[++cnt]=node{1,f,f};
            // printf("1 %lld %lld\n",f,f);
            f<<=1;
        }
        ans[++cnt]=node{2,x,y};
        x^=y;
    }
    write(cnt),putchar('\n');
    for(register int i=1;i<=cnt;i++){
        printf("%lld ",ans[i].a);
        if(ans[i].opt==1){
            putchar('+');
        }else{
            putchar('^');
        }
        printf(" %lld\n",ans[i].b);
    }
    return 0;
}

标签:输出,ch,下标,CSP6,样例,int,逆序
From: https://www.cnblogs.com/phigros/p/17583001.html

相关文章