[codeforces 1330B] Dreamoon Likes Permutations 合理分块

Codeforces Round #631 (Div. 2) - Thanks, Denis aramis Shitov!   比赛人数10889

[codeforces 1330B]  Dreamoon Likes Permutations  合理分块

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址https://codeforces.com/contest/1330/problem/B

Problem Lang Verdict Time Memory
B - Dreamoon Likes Permutations GNU C++11 Accepted 77 ms 2200 KB

比赛时,没有思路,最好的办法就是,拿出纸笔,模拟样例数据生成过程

5
1 4 3 2 1

2
1 4
4 1
模拟发现,对应排列数
1
4 3 2 1
1出现2次
1 4 3 2
1
1出现2次
一组排列数含1个元素,另一组排列数含4个元素
可这样分组,按自左往右序列,分成1个元素(最左边有1个元素);5-1=4个元素(最左边有4个元素).这两种情况。如下:
(1) (4 3 2 1)此种情况正确
(1 4 3 2) (1)此种情况正确


6
2 4 1 3 2 1

1
4 2
模拟发现,对应排列数
2 4 1 3
2 1
1出现2次,2出现2次
一组排列数含2个元素,另一组排列数含4个元素
可这样分组,按自左往右序列,分成2个元素(最左边有2个元素);6-2=4个元素(最左边有4个元素).这两种情况。如下:
(2 4) (1 3 2 1)此种情况错误
(2 4 1 3) (2 1)此种情况正确

4
2 1 1 3

0
模拟发现,找不到,对应排列数
1出现2次
一组排列数含2个元素,另一组排列数含2个元素
可这样分组,按自左往右序列,分成2个元素(最左边有2个元素);4-2=2个元素(最左边有2个元素).这两种情况。如下:
(2 1) (1 3)此种情况错误
(2 1) (1 3)此种情况错误


4
1 3 3 1

0
模拟发现,找不到,对应排列数
1出现2次,3出现2次
一组排列数含1个元素,另一组排列数含3个元素
可这样分组,按自左往右序列,分成1个元素(最左边有1个元素);4-1=3个元素(最左边有3个元素).这两种情况。如下:
(1) (3 3 1)此种情况错误
(1 3 3) (1)此种情况错误


12
2 1 3 4 5 6 7 8 9 1 10 2

1
2 10
模拟发现,对应排列数
2 1
3 4 5 6 7 8 9 1 10 2
1出现2次,2出现2次
一组排列数含2个元素,另一组排列数含10个元素
可这样分组,按自左往右序列,分成2个元素(最左边有2个元素);12-2=10个元素(最左边有10个元素).这两种情况。如下:
(2 1) (3 4 5 6 7 8 9 1 10 2)此种情况正确
(2 1 3 4 5 6 7 8 9 1) (10 2)此种情况错误

3
1 1 1

0
模拟发现,找不到,对应排列数
1出现3次
不符题意,无需再做后面的操作。

比赛时,代码写得一团糟,第一次提交WA,反复读题,觉得思路没有问题,每组输入数据,对应的输出数据的第一行输出情况,只有0,1,2,三种情况。

举些数据,突然想到神来一笔,找到关键数据如下

Input:
1
4
1 2 2 1
Output:
1
2 2

若上述数据能通过,该题的坑点也就跳过去了。

修改代码,提交AC.

比赛时,虽然提交的代码效率高,但感觉可读性差了许多,以下AC代码,为赛后重写代码,可读性高了许多。

#include <cstdio>
#include <algorithm>
#define maxn 200010
using namespace std;
int a[maxn],cnt[maxn],n,b[maxn];//b[]临时数组
int judge(int l,int r){//返回值0表明a[]在[l,r]区间的元素,不能构成排列数.返回值1表明a[]在[l,r]区间的元素,能构成排列数
	int i,m;
	m=r-l+1;
	for(i=1;i<=m;i++)b[i]=a[l+i-1];
	sort(b+1,b+1+m);//自小到大排序
	for(i=1;i<=m;i++)
		if(b[i]!=i)return 0;//判定b[]在[l,r]区间,是否是排列数
	return 1;
}
int main(){
	int t,i,b,k,l1,r1,l2,r2;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(i=1;i<=n;i++)cnt[i]=0;
		for(i=1;i<=n;i++)scanf("%d",&a[i]),cnt[a[i]]++;
		b=0;
		for(i=1;i<=n;i++)
			if(cnt[i]==2)b=i;//记录最短排列数中元素的最大值
			else break;
		if(b==0)printf("0\n");
		else{
			k=0,l1=0,r1=0,l2=0,r2=0;
			if(judge(1,b)&&judge(b+1,n))k++,l1=b,r1=n-b;
			if(judge(1,n-b)&&judge(n-b+1,n))k++,l2=n-b,r2=b;
			if(k==2){
				if(b==n-b){//可能遇到排列数元素个数相同的情况。
					printf("1\n");
					printf("%d %d\n",b,n-b);
				}else{
					printf("2\n");
					printf("%d %d\n",b,n-b);
					printf("%d %d\n",n-b,b);
				}
			}else if(k==1){//需判定该输出b n-b,还是n-b b
				printf("1\n");
				if(l1)printf("%d %d\n",l1,r1);
				else printf("%d %d\n",l2,r2);
			}else printf("0\n");//找不到排列数
		}
	}
	return 0;
}
发布了660 篇原创文章 · 获赞 562 · 访问量 48万+

猜你喜欢

转载自blog.csdn.net/mrcrack/article/details/105307964