20191112 csp-s模拟T3(字符串)

T1 命令方块(block)

(WOJ4816)
1.1 题目描述
实际上这道题与命令方块没有什么关系。给定 n n n个字符串 s i s_i si,将它们按给出的顺序排开。你每次可以交换任意两个字符串的位置。
通过交换,这些字符串最终需要满足如下的性质:
对于任意的 i < j < k i < j < k i<j<k,必须有: l c p ( s i , s j ) ≤ l c p ( s i , s k ) lcp(s_i,s_j)\le lcp(s_i,s_k) lcp(si,sj)lcp(si,sk)以及 l c p ( s j , s k ) ≤ l c p ( s i , s k ) lcp(s_j,s_k)\le lcp(s_i,s_k) lcp(sj,sk)lcp(si,sk)。其中 l c p ( s , t ) lcp(s,t) lcp(s,t)的定义为:字符串 s s s t t t 的最长公共前缀的长度。如 l c p ( ” a b c ” , ” a b d ” ) = 2 lcp(”abc”,”abd”) = 2 lcp(abc,abd)=2,而 l c p ( ” a b c ” , ” a b c d ” ) = 3 lcp(”abc”,”abcd”) = 3 lcp(abc,abcd)=3
请按顺序输出你交换了哪些字符串。保证存在一种方案,使得交换之后所有字符串满足上述性质。并且可以证明,在题目给定的范围下,这样的方案一定存在,并且你所需要的最少交换次数不会超过 1 0 6 10^6 106次。
1.2 输入描述
输入文件名为block.in。
第一行为一个正整数 n n n,代表字符串的个数。
接下来 n n n行,每行一个字符串,代表最初的 s i s_i si
1.3 输出描述
输出文件名为block.out。
第一行为一个正整数 m m m,代表你的交换次数。
接下来 m m m行,每行两个正整数 a , b a,b a,b,代表你交换的两个字符串的编号。
Special Judge将会按顺序完成你给出的交换操作,并判定最后得到的字符串序列是否合法。如果你输出的 m m m大于 1 0 6 10^6 106,或者输出格式不正确,将被认为是答案错误。如果你的答案合法并且是正确的,你将会得到对应测试点的得分,反之不得分。
1.4 输入样例&输出样例
block1.in
3
abcd
a
abd
block1.out
1
1 2
另外给出了一个附加样例。
1.5 样例说明
对于第一个样例:
交换后的字符串序列为: a , a b c d , a b d a,abcd,abd a,abcd,abd,不难发现,这是符合要求的。
对于全部的数据, n ≤ 1 0 6 , ∑ ∣ s i ∣ ≤ 1 0 7 n\le 10^6,\sum |s_i|\le 10^7 n106,si107,字符串中的所有字符均属于小写英文字母。

思路:
发现建出字典树后,任意一种 d f s 序 dfs序 dfs都满足要求,不妨使它为字典序,直接 s o r t sort sort
关于字典序符合要求的证明:
对于 i < j < k i<j<k i<j<k,字符串 j j j必定分别与字符串 i i i k k k的相似度最高。

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()

inline int in{
	int s=0,f=1;char x;
	for(x=getchar();!isdigit(x);x=getchar())    if(x=='-')  f=-1;
	for( ;isdigit(x);x=getchar())   s=(s<<1)+(s<<3)+(x&15);
	return s*f;
}

const int A=1e7+5;
const int B=1e6+5;
int n;
struct Qur{
	string ch;
	int id;
	inline friend bool operator < (const Qur &x,const Qur &y){
		return x.ch<y.ch;
	}
}p[B];
int ans;
vector <pair<int,int> > q;

signed main(){
	n=in;
	for(int i=1;i<=n;i++){
		cin>>p[i].ch;
		p[i].id=i;
	}
	sort(p+1,p+1+n);
	for(int i=1;i<=n;i++){
		if(p[i].id==i)    continue;
		while(p[i].id!=i){
			q.push_back(make_pair(i,p[i].id));
			swap(p[i],p[p[i].id]);
			ans++;
		}
	}
	printf("%d\n",ans);
	for(int y=q.end()-q.begin()-1;y>=0;y--)
		printf("%d %d\n",q[y].first,q[y].second);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值