重庆市noip2016模拟round4 BSOJ4874 排序

想要看随机化的可以看看我的这篇文章
BSOJ4874 -- 【NOIP2016-4】 排序  (noip模拟)
Description
shell 排序是众多排序算法中的一种。给定 N 个整数,存放在数组 A 中,排成升序。下表是两种不同语言的排序程序代码段:
此处的 i, N, X, gap, temp, ok 均是整数。数组 A 的元素互不相同,取值范围在 1~N 之间。如果第 11 行被遗漏了,这个有 bug 的 shell 排序程序在 X 取某些值时,仍然有可能得到正确的排序结果。
请你找出所有能得到正确排序结果的 X。
Input
第1 行:1 个整数 N,表示要排序的元素个数
第2 行:N 个整数,表示要排序的数组 A,保证初始状态非升序。
Output
第1 行:1 个整数 C,表示 X 有多少种不同的取值方案,能得到正确排序结果
第2 行:C 个整数,表示能得到正确排序结果的 X 的取值,升序排列
Sample Input
6
4 2 6 1 5 3
Sample Output
2
1 3
Hint
[样例说明]
有 6 个元素,分别是 4, 2, 6, 1, 5, 3。能得到正确的排序结果的 X 有 2 种取值方案:
•X = 1, 我们交换以下这些位置的元素
(1,2), (3,4), (4,5), (5,6), (2,3), (4,5), (1,2), (3,4);
•X = 3, 我们交换以下这些位置的元素
(1,4), (3,6).
[数据说明]
•1 < N <= 500000
•1 ≤ X ≤ N-1

先给随机化乱搞。
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstdio>
using namespace std;
int n;
int r[500009]={0};
int fir[109]={0};
int sec[109]={0};
bool possible[500009]={0};
void Get_firsec(int x,int i)
{
    int yao=0x3fffffff,er=0x3fffffff;
    while(x<=n)
    {
        if(r[x]<yao)
        {
            er=yao;
            yao=r[x];
            x+=i;
            continue;
        }
        er=min(er,r[x]);
        x+=i;
    }
    fir[0]++;
    fir[fir[0]]=yao;
    sec[0]++;
    sec[sec[0]]=er;
}
void Solve_belief()
{
    srand(time(NULL));
    int pos,t;
    bool ok;
    for(int i=n;i>=1;i--)
    {
        if(possible[i])continue;
        fir[0]=0;
        sec[0]=0;
        ok=1;
        t=min(100,i);
        for(int j=0;j<=t-1;j++)
        {
            pos=(rand()%(i/t))+1;
            pos=j*(i/t)+pos;
            Get_firsec(pos,i);
            if(j>=1)
            {
                if(fir[j]>fir[j+1]){ok=0;break;}
                if(sec[j]>sec[j+1]){ok=0;break;}
            }
        }
        if(ok==0)continue;
        possible[i]=1;
        for(int j=1;j*j<=i;j++)
        {
            if(i%j==0)
            {
                possible[j]=1;
                possible[i/j]=1;
            }
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++)if(possible[i])cnt++;
    cout<<cnt<<endl;
    for(int i=1;i<=n;i++)if(possible[i])printf("%d ",i);
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&r[i]);
    Solve_belief();
    fclose(stdout);
    return 0;
}


正解如下,有一个归位的思想即可。
#include<iostream>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,cnt=0,h[500005],c1=0;
inline int gcd(int a,int b)
{
        if(b==0) return a;
        return gcd(b,a%b);
}
int main(){
        cin>>n;
        int x;
        int G=0;
        for(int i=1;i<=n;i++)
        {
                scanf("%d",&x);
                if(x!=i)
                {
                        if(!G) G=abs(x-i);
                        else G=gcd(G,abs(x-i));
                }
        }
        int c1=0;
        for(int i=1;i<=G;i++)
          if(G%i==0)c1++,h[c1]=i;
        sort(h+1,h+c1+1);
        cout<<c1<<endl;
        for(int i=1;i<=c1;i++)
          cout<<h[i]<<" ";
        return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值