二次元音游人

这是一股照亮混沌的令和时代互联网的一道光,给在电子的海洋里冲浪的阿宅们带来笑容

CSP6

T1 A. 排序

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

输入格式
第一行输入 \(n\),第二行输入数组a。保证是排列。

输出格式
如果不存在答案,输出 \(-1\)

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

样例
样例输入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;
}

用到了dp

点击抄袭代码
#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('\n');
    }
}
using namespace Testify;
int x,y,n,mod;
int Tempestissimo(0);
const int N=1e5+5;
int f[N],g[320][N];
inline int solve(int x){//拆成只有>=xの限制
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    int m=sqrt(n);
    f[0]=g[0][0]=1;
    for(register int i=x;i<=m;i++){//第几个种类
        for(register int j=i;j<=n;j++){//i选了多少个
            f[j]=(f[j]+f[j-i])%mod;
        }
    }

    int m1=max(m,x-1);
    for(register int i=0;i<=m;i++){
        for(register int j=0;j<=n;j++){
            if(i&&i+j<=n){
                g[i][j+i]+=g[i][j];
                g[i][j+i]%=mod;
            }
            if(j+m1+1<=n){
                g[i+1][j+m1+1]+=g[i][j];
                g[i+1][j+m1+1]%=mod;
            }
        }
    }
    int ans=0;
    for(register int i=0;i<=m;i++){
        for(register int j=0;j<=n;j++){
            ans+=(g[i][j]*f[n-j]%mod)%mod;
            ans%=mod;
        }
    }
    return ans;
}
signed main(void){
    x=read(),y=read(),n=read(),mod=read();
    write((solve(x)-solve(y+1)+mod)%mod);
    return 0;
}
posted @ 2023-07-26 19:48  超绝最可爱天使酱  阅读(69)  评论(2)    收藏  举报