牛客暑假多校训练营(第十场)A- Permutation-dfs,构造,规律

在这里插入图片描述
在这里插入图片描述
题意:给定一个素数p,用1,2,。。。p-1,进行排序,排序的序列必须符合第(x+1)位=第x位2%p,或者第(x+1)位=第x位3%p,请你构造这样一个序列。
思路:
(1)dfs递归来找,因为第一位肯定是1,之后的2~p-1位,有两种情况,2或者3,所以分别来找,然后回溯。递归出口一个是两种情况都不满足,所以往回来回溯,另一个是,计数达到了p-1位的时候,就证明已经达到的一个序列,然后退出。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;
int a[N];
bool vis[N];
int f;int p;
void dfs(int x,int cnt)//数值,步数
{
    if(cnt==p-1){//如果步数达到了p-1位,就退出
        f=1;//标记,如果有符合的序列就输出
        for(int i=1;i<=cnt;i++){
            if(i!=cnt)
                printf("%d ",a[i]);
            else
                printf("%d\n",a[i]);
        }
        return ;
    }
    int q=x*2%p;//*2的情况
    int qq=x*3%p;//*3的情况
    if(q>=1&&q<=p-1&&vis[q]==0){//范围判断,是否被用过
        vis[q]=1;a[cnt+1]=q;//标记下来,cnt+1就是下一位
        dfs(q,cnt+1);//去找下一位
        vis[q]=0;//回溯时标记清空
    }
    else if(qq>=1&&qq<=p-1&&vis[qq]==0){
        vis[qq]=1;a[cnt+1]=qq;
        dfs(qq,cnt+1);
        vis[qq]=0;
    }
    return ;//两种情况都不可以,就回溯递归出口
}
int main ()
{
   int t;scanf("%d",&t);
   while(t--){
        memset(a,0,sizeof(a));
        memset(vis,0,sizeof(vis));//初始化
        scanf("%d",&p);
        vis[1]=1;a[1]=1;f=0;
        dfs(1,1);//dfs来找
        if(f==0)
            printf("-1\n");//如果没有合适的,就输出-1
   }
   return 0;
}

(2)分析下来,有一种构造规律,可以用2,就先2,2使不了,在进行3,如果两者都不行,就-1了。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;
int a[N];
bool vis[N];
int main ()
{
    int t;scanf("%d",&t);
    while(t--){
        memset(a,0,sizeof(a));
        memset(vis,0,sizeof(vis));//初始化
        int p;scanf("%d",&p);
        int k=0;a[++k]=1;vis[1]=1;
        int f=0;
        for(int i=2;i<=p-1;i++){//有2~p-1位数字
            int q=2*a[k]%p;//先*2来判断
            if(q>=1&&q<=p-1&&vis[q]==0){
                vis[q]=1;a[++k]=q;continue;//如果有,就继续,不用找*3
            }
            int qq=3*a[k]%p;//之后*3判断
            if(qq>=1&&qq<=p-1&&vis[qq]==0){
                vis[qq]=1;a[++k]=qq;
            }
            else{
                f=1;break;//如果*2,*3都找不到了,就退出,输出-1
            }
        }
        if(f==1){
            cout<<"-1"<<endl;
        }
        else{
            for(int i=1;i<=k;i++){//输出答案
                if(i!=k) printf("%d ",a[i]);
                else printf("%d\n",a[i]);
            }
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值