UVa Problem 10252 Common Permutation (公共排列)

本文介绍了一个简单的公共排列算法实现过程,通过对比两个字符串并找出它们共有的字符。该算法首先对输入的字符串进行字典序排序,然后遍历两个字符串找到相同字符并输出。这是一种基础的字符串处理和算法训练题目。
// Common Permutation (公共排列)
// PC/UVa IDs: 110303/10252, Popularity: A, Success rate: average Level: 1
// Verdict: Accepted
// Submission Date: 2011-05-22
// UVa Run Time: 0.044s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
	
#include <iostream>
#include <algorithm>
	
using namespace std;
	
bool cmp(char a, char b)
{
	return a < b;
}
	
int main(int ac, char *av[])
{
	string a;
	string b;
	
	while (getline(cin, a), getline(cin, b))
	{
		// 比较前先按字典排序,保证输出的是字典序。
		sort(&a[0], &a[0] + a.length(), cmp);
		sort(&b[0], &b[0] + b.length(), cmp);
		
		// 查找共有的字符,不同的忽略。
		int i = 0;
		int j = 0;
		while (i < a.length() && j < b.length())
		{
			if (a[i] == b[j])
			{
				cout << a[i];
				i++;
				j++;
			}
			else
			{
				if (a[i] < b[j])
					i++;
				else
					j++;
			
			}
		}
		cout << endl;
	}
	
	return 0;
}


Another Permutation Problem 是 Codeforces Round 892 (Div. 2) 中的 C 题,属于纯数学方法的思维题。 在解决该问题时,有多种不同的代码实现方式。一种实现方式使用了标准输入输出流和数组,通过多次循环计算得出结果。代码如下: ```cpp #include <iostream> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <stack> #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; const int maxn = 550; long long s[maxn]; int main(){ int t; cin >> t; while(t--){ long long n; cin >> n; long long ans = 0; s[0] = 0; for(long long i = 1;i <= n;i++){ s[i] = s[i-1]+i*i; } for(long long i = 1;i <= n;i++){ long long sum = s[i-1]; long long maxl = 0; long long temp; for(long long j = i;j <= n;j++){ temp = (n-(j-i))*j; sum += temp; if(temp>maxl){ maxl = temp; } } sum -= maxl; if(sum>ans){ ans = sum; } } cout << ans << endl; } return 0; } ``` 还有一种实现方式使用了`bits/stdc++.h`头文件和`vector`容器,通过`reverse`函数翻转数组来计算结果,代码如下: ```cpp #include<bits/stdc++.h> #define ll long long using namespace std; void solve() { int n; cin>>n; vector<int>v(n); iota(v.begin(),v.end(),1); int ans=0,sum=0,mx=0; for(int i=0;i<n;i++){ reverse(v.begin()+i,v.end()); mx=0,sum=0; for(int j=0;j<n;j++){ sum+=v[j]*(j+1); mx=max(mx,v[j]*(j+1)); } ans=max(ans,sum-mx); reverse(v.begin()+i,v.end()); } cout<<ans<<'\n'; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; cin>>t; while(t--) solve(); return 0; } ``` 此外,还有一种实现方式是先进行初始化操作,然后通过循环枚举不同长度的翻转区间来计算结果,代码如下: ```cpp #include<iostream> #include<algorithm> using namespace std; //证明:逆序一定是最小的,正序一定是最大的(不删减的情况下) int a[500]; int main(){ int t; cin>>t; while(t--){ int n; cin>>n; for(int i=1;i<=n;i++){ a[i]=i; } int ans=0; for(int len=1;len<=n;len++){ int res=0; int tmp=0; for(int i=0;i<=n-len;i++){ res+=a[i]*i; tmp=max(tmp,a[i]*i); } for(int i=n-len+1,j=n;i<=n;i++,j--){ res+=a[i]*j; tmp=max(tmp,a[i]*j); } res-=tmp; ans=max(ans,res); } cout<<ans<<endl; } } ``` 在赛时做法中,有人采用了官方题解的做法,即枚举`i×j`,不过使用并查集进行维护;而官方题解的维护方式是从`n`倒序枚举到`1`,对于当前数字,找到小于`M/x`的还没被用过的最大的数字,通过维护一个栈,利用`M/x`单调递增的特性,将新增加的可行的数放进栈里,然后弹出栈顶 [^3]。 也可以通过算`n = 1,2,3,4`的情况,发现可以枚举`i`,让`i`前的数顺序排列,从`i`开始逆序排列,进而计算出最大值 [^5]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值