Codeforces Round #201 (Div. 2)

A. Difference Row
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You want to arrange n integers a1, a2, ..., an in some order in a row. Let's define the value of an arrangement as the sum of differences between all pairs of adjacent integers.

More formally, let's denote some arrangement as a sequence of integers x1, x2, ..., xn, where sequence x is a permutation of sequencea. The value of such an arrangement is (x1 - x2) + (x2 - x3) + ... + (xn - 1 - xn).

Find the largest possible value of an arrangement. Then, output the lexicographically smallest sequence x that corresponds to an arrangement of the largest possible value.

Input

The first line of the input contains integer n (2 ≤ n ≤ 100). The second line contains n space-separated integers a1a2...an(|ai| ≤ 1000).

Output

Print the required sequence x1, x2, ..., xn. Sequence x should be the lexicographically smallest permutation of a that corresponds to an arrangement of the largest possible value.

Sample test(s)
input
5
100 -100 50 0 -50
output
100 -50 0 50 -100 
题意
给n个数,然后求一个字典序最小,且两两相邻元素差和最大的序列
思路
根据公式sum = (a1-a2)+(a2-a3)+……(an-1 - an)可以看出,中间元素被抵消,只要a1-an最大就行了,所以先整体从大往小排遍,然后中间从小往大,字典序就是最小了
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
int n,num[105];
int cmp(int a,int b){
	return a>b;
}
int cmp2(int a,int b){
	return a<b;
}
int main(void){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>num[i];
	}
	sort(num,num+n,cmp);
	sort(num+1,num+n-1,cmp2);
	for(int i=0;i<n;i++){
		cout<<num[i]<<" ";
	}
	
	return 0;
}

B. Fixed Points
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

A permutation of length n is an integer sequence such that each integer from 0 to (n - 1) appears exactly once in it. For example, sequence [0, 2, 1] is a permutation of length 3 while both [0, 2, 2] and [1, 2, 3] are not.

A fixed point of a function is a point that is mapped to itself by the function. A permutation can be regarded as a bijective function. We'll get a definition of a fixed point in a permutation. An integer i is a fixed point of permutation a0, a1, ..., an - 1 if and only if ai = i. For example, permutation [0, 2, 1] has 1 fixed point and permutation [0, 1, 2] has 3 fixed points.

You are given permutation a. You are allowed to swap two elements of the permutation at most once. Your task is to maximize the number of fixed points in the resulting permutation. Note that you are allowed to make at most one swap operation.

Input

The first line contains a single integer n (1 ≤ n ≤ 105). The second line contains n integers a0, a1, ..., an - 1 — the given permutation.

Output

Print a single integer — the maximum possible number of fixed points in the permutation after at most one swap operation.

Sample test(s)
input
5
0 1 3 4 2
output
3
题意
给n个数,下标从0开始,若a[i]=i,则答案+1,问只给一次机会,可以交换任意两个数,最大的结果是多少
思路
其实也就3种情况,要么+2要么+1要么不变。+2显然是两个数可以归位,+1只能一个数归位,+0要么数字全部都归位了,要么存在有多个相同数值的情况且其中一个数字已经归位了
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
int n,num[100005];
int main(void){
	cin>>n;
	for(int i=0;i<n;i++) cin>>num[i];
	int cou=0;
	for(int i=0;i<n;i++)
		if(num[i]==i) cou++;
	int flag=0;
	for(int i=0;i<n;i++)
		if(num[i]!=i){
			int now = num[i];
			if(num[now]==i)
				flag=2;
			else if(num[now]==num[i]) continue;
			else flag = max(flag,1);
		}
	printf("%d\n",cou+flag);
	return 0;
}

C. Alice and Bob
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

It is so boring in the summer holiday, isn't it? So Alice and Bob have invented a new game to play. The rules are as follows. First, they get a set of n distinct integers. And then they take turns to make the following moves. During each move, either Alice or Bob (the player whose turn is the current) can choose two distinct integers x and y from the set, such that the set doesn't contain their absolute difference |x - y|. Then this player adds integer |x - y| to the set (so, the size of the set increases by one).

If the current player has no valid move, he (or she) loses the game. The question is who will finally win the game if both players play optimally. Remember that Alice always moves first.

Input

The first line contains an integer n (2 ≤ n ≤ 100) — the initial number of elements in the set. The second line contains n distinct space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109) — the elements of the set.

Output

Print a single line with the winner's name. If Alice wins print "Alice", otherwise print "Bob" (without quotes).

Sample test(s)
input
2
2 3
output
Alice
题意
给n个数,两个人轮流进行,轮到的时候从集合中抽取两个元素X,Y使得其绝对值差集合中不存在,如果某一方找到则输。Alice先手
思路
其实跟XY如何取没什么关系。因为最终集合中元素的个数肯定是固定的,问题就变成需要填补多少个数,即是能进行多少回合。而集合中的元素,稍微列几项出来就会发现其实跟gcd有关,只要求出所有数的gcd值以及找到所有数中最大的元素,集合中的元素就是MAX以内gcd的倍数。
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
int num[105];
int main(void){
	int n;

	int gg;
	cin>>n;
	int MAX=0;
	for(int i=1;i<=n;i++){
		cin>>num[i];
		if(i==1) gg=num[i];
		else gg=__gcd(gg,num[i]);
		MAX=max(MAX,num[i]);
	}
	int tt = MAX/gg-n;
	if(tt%2) printf("Alice\n");
	else printf("Bob\n");
	
	
	
	return 0;
}

D. Lucky Common Subsequence
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

In mathematics, a subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements. For example, the sequence BDF is a subsequence of ABCDEF. A substring of a string is a continuous subsequence of the string. For example, BCD is a substring of ABCDEF.

You are given two strings s1s2 and another string called virus. Your task is to find the longest common subsequence of s1 and s2, such that it doesn't contain virus as a substring.

Input

The input contains three strings in three separate lines: s1s2 and virus (1 ≤ |s1|, |s2|, |virus| ≤ 100). Each string consists only of uppercase English letters.

Output

Output the longest common subsequence of s1 and s2 without virus as a substring. If there are multiple answers, any of them will be accepted.

If there is no valid common subsequence, output 0.

Sample test(s)
input
AJKEQSLOBSROFGZ
OVGURWZLWVLUXTH
OZ
output
ORZ
题意
给出3个字符串,题意中给出子串跟子序列的定义。你需要找出s1,s2不包含virus这个子串的最大公共子序列。
思路
另3个子串为A、B、C。
一开始我想着找包含尽可能少的公共子序列再贪心把里面的某些点删除使它可以不包含C,但发现没法只根据C进行删点它跟原序列有关。
例如公共子序列为SSSDD C为SD,你就得删了两个D,而SSDDD你又得删了两个S,没法只根据SD来判断到底删哪一个。
还有CACAC C为CAC,公共子序列出现了两次CAC,显然删除公共的C是最优的,总之贪心肯定是没办法搞的。
 
   
后来看了题解其实只要在求最大公共子序列的时候不出现转移到C结尾的状态就行了,并记录路径。
首先先要知道如何求最大公共子序列,这个需要动态规划来求解
A[i]==B[j]的时候dp[i][j]=dp[i-1][j-1]+1,否则dp[i][j]=max(dp[i-1][j],dp[i][j-1])
因为需要记录当前后缀是C中哪个前缀,所以需要开三维dp[i][j][k],k表示当前跟C所能匹配的最长前缀长度
若当前状态为k,且满足A[i]==B[j],你就需要对状态进行转移,若C[k+1]!=A[i],不能简单的从头开始,需要跳转到子后缀直到C[k+1]!=A[i],或者k==0且
C[k+1]!=A[i]的情况,即是跟C毫无关系的状态。这里跳转需要用到kmp的知识,需要先对C进行构造,并且在失配的时候用kmp的思想进行匹配。
我们需要在转移的时候,知道当前的路径,这里用pre[i][j][k][3]跟last[i][j][k][3]来保存路径,pre是对应前一个结点的状态,last是真实的最终状态,因为在dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k])的时候我们需要保留真实的最终状态,这里取最大的同时,pre跟last都得取对应的那个。而最后一维3个元素对应i,j,k三个数值。找路径的时候从后往前用pre不断跳转,并取所有的A[i],直到i最终为0
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
char A[105],B[105],C[105];

int next[105]; 
int dp[105][105][105];
int pre[105][105][105][3],last[105][105][105][3];
void gznext(char *t){
	memset(next,0,sizeof(next));
	int j=next[0]=-1,i=0;    //next第一位为-1 
	while(t[i]){
		if(j==-1||t[i]==t[j]){ //为-1即第一位不匹配 
			i++;
			j++;
			next[i]=j;
		}
		else j=next[j];      //返回上一次匹配到的位置 
	}
}
int main(void){
	scanf("%s%s%s",A+1,B+1,C+1);
	gznext(C+1);
	int lena = strlen(A+1);
	int lenb = strlen(B+1);
	int lenc = strlen(C+1);
	for(int i=1;A[i];i++){
		for(int j=1;B[j];j++){
			for(int k=0;k<lenc;k++){
				int a,b,c;
				if(dp[i][j-1][k]>=dp[i-1][j][k])
					a=i,b=j-1,c=k;
				else a=i-1,b=j,c=k;
				if(dp[a][b][c]>dp[i][j][k]){
					dp[i][j][k] = dp[a][b][c];
					for(int l=0;l<3;l++){
						pre[i][j][k][l] = pre[a][b][c][l];
						last[i][j][k][l] = last[a][b][c][l];
					}
				}				
				
				if(A[i]==B[j]){
					if(dp[i-1][j-1][k]==0&&k>0) continue; 
					int kk=k;
					while(1){
						if(kk==0&&A[i]!=C[kk+1]){
							if(dp[i-1][j-1][k]+1>dp[i][j][kk]){
								dp[i][j][kk] = dp[i-1][j-1][k]+1;
								for(int l=0;l<3;l++)
									pre[i][j][kk][l]=last[i-1][j-1][k][l];
								last[i][j][kk][0]=i;
								last[i][j][kk][1]=j;
								last[i][j][kk][2]=kk;
							}
							
							break;
						}
						
						if(A[i]==C[kk+1]){
							if(dp[i-1][j-1][k]+1>dp[i][j][kk+1]&&kk+1!=lenc){
								dp[i][j][kk+1] = dp[i-1][j-1][k]+1;
								for(int l=0;l<3;l++)
								pre[i][j][kk+1][l]=last[i-1][j-1][k][l];
								last[i][j][kk+1][0]=i;
								last[i][j][kk+1][1]=j;
								last[i][j][kk+1][2]=kk+1;
							}	
							break;
						}
						kk = next[kk];
					}	
				}
			}
		}
	}
	int MA=0,kk;
	for(int i=0;i<lenc;i++)
		if(dp[lena][lenb][i]>MA){
			MA=dp[lena][lenb][i];
			kk=i;
		}
	if(MA==0) printf("0\n");
	else {
		stack<char> S;
		S.push(A[last[lena][lenb][kk][0]]);
		int i=pre[lena][lenb][kk][0];
		int j=pre[lena][lenb][kk][1];
		int k=pre[lena][lenb][kk][2];
		while(i!=0){
			S.push(A[i]);
			int ii,jj,kk;
			ii=pre[i][j][k][0];
			jj=pre[i][j][k][1];
			kk=pre[i][j][k][2];
			i=ii,j=jj,k=kk;
		}
		while(!S.empty()){
			printf("%c",S.top());
			S.pop();
		}
	}
	return 0;
}



E. Number Transformation II
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a sequence of positive integers x1, x2, ..., xn and two non-negative integers a and b. Your task is to transform a into b. To do that, you can perform the following moves:

  • subtract 1 from the current a;
  • subtract a mod xi (1 ≤ i ≤ n) from the current a.

Operation a mod xi means taking the remainder after division of number a by number xi.

Now you want to know the minimum number of moves needed to transform a into b.

Input

The first line contains a single integer n (1 ≤  n ≤ 105). The second line contains n space-separated integers x1, x2, ..., xn(2 ≤  xi ≤ 109). The third line contains two integers a and b (0  ≤ b ≤  a ≤ 109a - b ≤ 106).

Output

Print a single integer — the required minimum number of moves needed to transform number a into number b.

Sample test(s)
input
3
3 4 5
30 17
output
6
题意
给出n个数,以及a跟b,你有两种操作,要么a-1,要么a-a%x[i],问最终由a变到b需要多少步
思路
由于元素有可能重复,所以需要对所有元素去重。然后得知道一点,如果a-a%x[i]如果小于b,那以后无论如何变a-a%x[i]仍然会小于b,所以x的个数会逐渐递减。接下来就是贪心,每次取a-1跟a-a%x[i]最小的数,直到a==b
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
int n;
int num[100005];
int a,b;
int main(void){
	cin>>n;
	for(int i=0;i<n;i++) cin>>num[i];
	cin>>a>>b;
	sort(num,num+n);
	int len = unique(num,num+n)-num;
	int ans=0;
	while(a>b){
		int t=a-1;
		for(int i=0;i<len&&i>-1;i++){
			if(a-a%num[i]<b)
				num[i--]=num[--len];
			else t = min(t,a-a%num[i]);
		}
		ans++;
		a = t;
	}
	printf("%d\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值