Codeforces Lucky Permutation Triple

构造类问题,打表找规律

题意:输入n,生成一个n的全排列a,生成一个n的全排列b,从第1位到第n位,每个位上的对应的(ai+bi)%n=ci,然后得到n位的序列c,看看c是不是也是一个n的全排列,是的话就成功了,输出。如果无论怎样都找不到合适的a和b去构造出c,那么就输出-1

这题一想通了,仅是那么的水,但是自己还是很长时间去思考

说说思考的过程

1.很容易想到,题目是想我们我们构造一个合适的a,b,进而产生合适的c,虽然题目让我们输出任意一个合法的排列就可以了,但其实要我们找的不是排列方案,而是匹配方案

试想一下,如果手头上有合适的一个排列,那么我们把对应的ai,bi,ci捆版在一次,我们完全可以对这个排列进行重新排列(重新排列时,捆版的元素要一起移动),这样我们可以重新排除n!个排列,都是合法的,因为对应位在一起。

所以我们得到一个结论,要么无解,要是有解的话,解的个数至少为n!(对于n=1也成立,n=1比较特殊,就是0 0 0),因为可能存在多种匹配方案

2.有上面的结论远远不够解题,这时候我就想用暴力先打表看看当n较小的时候会有什么规律可循,但是没有电脑就一直手写。终于推到8的时候,发现n为偶数的时候都是无解,后来用电脑暴力打表也证实了这个规律

3.但是对于n为奇数的情况,还是没有一个很好的解决方案,最终还是靠电脑打表,才发现了这是个水题,只要a和b都是0 1 2 3 4……n-1的时候,就必然是一个可行解

所以就这样解决了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010

int main()
{
    int n;
    cin >> n;
    if(!(n&1)) cout << -1 << endl;
    else
    {
        for(int i=0; i<n; i++) cout << i << " "; cout << endl;
        for(int i=0; i<n; i++) cout << i << " "; cout << endl;
        for(int i=0; i<n; i++) cout << (2*i)%n << " "; cout << endl;
    }
    return 0;
}

打表程序

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010

int a[N],b[N],c[N];
bool ok,usedb[N],usedc[N];

void dfs(int n,int cur)
{
    if(cur >= n) 
    {
        ok =true;
        cout << "可行解" << endl;
        for(int i=0; i<n; i++) cout << a[i] << " "; cout << endl;
        for(int i=0; i<n; i++) cout << b[i] << " "; cout << endl;
        for(int i=0; i<n; i++) cout << c[i] << " "; cout << endl;
        return ;
    }
    for(int i=0; i<n; i++)
        if(!usedb[i] && !usedc[ (a[cur]+i)%n ])
        {
            usedb[i] = usedc[ (a[cur]+i)%n ] = true;
            b[cur] = i; c[cur] = (a[cur]+i)%n;
            dfs(n,cur+1);
            usedb[i] = usedc[ (a[cur]+i)%n ] = false;
        }
}

void solve(int n)
{
    memset(usedb,false,sizeof(usedb));
    memset(usedc,false,sizeof(usedc));
    for(int i=0; i<n; i++) a[i] = i;
        
    dfs(n,0);  
    if(!ok) cout << "无解" << endl;    
}

int main()
{
    freopen("BF.txt","w",stdout);
    for(int n=1; n<=10; n++)
    {
        printf("%d:_______________\n",n);
        solve(n);
        cout << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3131696.html