列表

详情


NC23996. CSL 的拼图

描述

众所周知 CSL 不仅玩魔方很强,打麻将也很强。今天他打魔法麻将的时候,在路上撞到了一个被打乱的 n 维魔法拼图。每一块拼图的位置用一个 n 维的坐标 来表示。将拼图的任意两块交换位置称为一步。CSL 赶着打魔法麻将时间很紧,对步数和时间也很严格,所以需要用恰好 t 步把拼图复原。请问他能做到吗?

输入描述

第一行有一个整数 n,表示拼图的维数。

第二行有 n 个整数 ,分别表示每一维的大小。

下面 行,每行有 n 个整数:第 行表示 第 i 块拼图的初始位置 ,第 行表示第 i 块拼图的目标位置 ,保证不会有多个拼图在同一初始位置或目标位置。

最后一行有一个整数 t,表示 CSL 要求的步数。





输出描述

如果 CSL 可以用恰好 t 步复原,在一行输出 "YES",否则输出 "NO"。

示例1

输入:

1
1
1
1
1

输出:

NO

示例2

输入:

2
2 2
1 2
2 1
1 1
2 2
2 1
1 2
2 2
1 1
2

输出:

YES

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 7ms, 内存消耗: 504K, 提交时间: 2019-04-03 19:42:32

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1000005],b[1000005],m[1000005],d[15]={1},t,c,n,len=1;
bool mark[1000005];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&d[i]);
		len*=d[i];
	}
	for(int i=0;i<len;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&t);
			a[i]=a[i]*d[j]+t-1;
		}
		for(int j=1;j<=n;j++){
			scanf("%d",&t);
			b[i]=b[i]*d[j]+t-1;
		}
	}
	for(int i=0;i<len;i++)m[a[i]]=i;
	int loop=0;
	for(int i=0;i<len;i++)
	if(!mark[i]){
		int j=i;
		while(!mark[j]){
			mark[j]=1;
			j=m[b[j]];
		}
		loop++;
	}
	scanf("%d",&t);
	t=len-loop-t;
	if(t>0||t&1)puts("NO");
	else puts("YES");
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 7ms, 内存消耗: 752K, 提交时间: 2020-04-18 00:12:23

#include<bits/stdc++.h>
using namespace std;
map<string, int> mp;

int main()
{
    int n, i, j, m=1, t, num=0;
    cin>>n;
    int d[n];
    for(i=0; i<n; i++)
    {cin>>d[i];m*=d[i];}
    getchar();
    string a[m], b[m];
    for(i=0; i<m; i++)
    {
        getline(cin, a[i]);
        mp[a[i]]=i;
        getline(cin, b[i]);
    }
    cin>>t;
    for(i=0; i<m; i++)
    {
        if(mp[a[i]]==mp[b[i]]) continue;
        n=mp[b[i]];
        swap(a[i], a[n]);
        swap(mp[a[i]], mp[a[n]]);
        num++;
    }
    if(num==t||(t>num&&(t-num)%2==0)) cout<<"YES";
    else cout<<"NO";
    return 0;
}

上一题