Codeforces Round #719 (Div. 3)A-E个人题解


A.Do Not Be Distracted!

链接

https://codeforces.com/contest/1520/problem/A

题目大意

给定一段仅由26个字母组成的字符串,问对于这段字符串,每个字母是否只出现一次。(一段相同字母代表出现一次)

思路

用map记录每个相同字母的位置,每次计算当前字母的位置与上一次出现的位置的差值,差值不等于1的话则意味着出现了两次。

#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

const int N = 30;

map pre;

int main(void){
	IOS;
	int t;
	cin>>t;
	while( t-- ){
		int n;
		string str;
		cin >> n >> str;
		pre.clear();
		
		bool is_yes = true;
		for( int i = 0 ; i < n ; i++ ){
			if( pre[str[i]] == 0 ){
				pre[str[i]] = i+1;
			}
			else if( i + 1 - pre[str[i]] != 1 ){
				is_yes = false;
				break;
			}
			else pre[str[i]] = i+1;
		}
		
		if( is_yes ) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

B. Ordinary Numbers

链接

https://codeforces.com/contest/1520/problem/B

题目大意

我们称11,22,33,这些由单一数字组成的为普通数字,现给出一个n,询问其中普通数字个数。

思路

1-9中有9个普通数字,10-99中有9个普通数字,每次倍增10倍,普通数字总数+9,而不满十倍关系的时候,观察第二位数是否比第一位数大,若大,必包含当前最高位的普通数字,若小,则不包含当前最高位的普通数字,例如7860包含7777,7680不包含7777。如此,对于任意n,我们可以求出理想状况下应满足的理想数目,再判断是否能够达到最高位的普通数字,若不能,理想数目-1即可。

#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

typedef long long LL;

int num[30];

LL solve( LL n ){
	if( n < 10 ) return n;
	
	LL bit = 0, m = n, ans = 0;
	while( m ){
		num[++bit] = m % 10;
		m /= 10; 
	}
	ans = (bit-1)*9 + num[bit]; //次一位的全部普通数字+最高位包含的普通数字。
	for( int i = bit-1; i >= 1 ; i -- ){
		if( num[i] > num[bit] ) break;
		if( num[i] < num[bit] ){
			ans--;
			break;
		}
	}
	return ans;
}

int main(void){
	IOS;
	int t;
	cin>>t;
	while( t-- ){
		LL n;
		cin>>n;
		cout << solve(n) << endl;
	}
	return 0;
}

C. Not Adjacent Matrix

链接

https://codeforces.com/contest/1520/problem/C

题目大意

给一个整数n,让你构造一个n*n的矩阵,里面任意元素之间差值的绝对值不等于1,每个元素都必须是1到n2之间的数字,且只能出现一次。问是否能够构造成功,可以则输出矩阵,不可以则输出-1;

思路

将每个元素分为奇偶两组,先填充奇数组,填充满了再填充偶数组。

代码
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

const int N = 110, M = 10000;

int g[N][N],a[M],b[M],cnt1,cnt2;

void inti(){
	for( int i = 1 ; i <= N*N ; i++ ){
		if( i % 2 == 1 ) a[++cnt1] = i;
		else b[++cnt2] = i;
	}
}

int main(void){
	IOS;
	int t;
	cin>>t;
	inti();//初始化先筛一遍
	while( t-- ){
		int n;
		cin >> n;
		if( n == 1 || n == 2 ){ cout << (n == 1 ? 1 : -1) << endl; continue ;}
		// n == 2 时候为1,2,3,4,无论如何放置,都必定存在差值绝对值为1的情况
		memset(g,0,sizeof g);
		
		bool is_yes = true;
		int step = 1;
		for( int i = 1 ; i <= n ; i++ )
			for( int j = 1 ; j <= n ; j++ ){
				if( a[step] > n*n  ){//奇数部分完毕,初始化step和更新分支条件
					is_yes = false;
					step = 1;
				}
				if( is_yes ) g[i][j] = a[step++];
				else g[i][j] = b[step++];
			}
		for( int i = 1 ; i <= n ; i++ )
			for( int j = 1 ; j <= n ; j++ )
				if( j == n ) cout << g[i][j] << endl;
				else cout << g[i][j] << " ";
	}
	return 0;
}

D. Same Differences

链接

https://codeforces.com/contest/1520/problem/D

题目大意

给你一个有n个元素的数组,询问有多少对(i,j)满足以下条件

\[i

思路

对条件进行恒等变式,就可以化成a[j] - j == a[i] - i,用map存一下每个元素减去下标的值即可,当第二次出现时候进行计算。

代码
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

const int N = 2*1e5+10;

typedef long long LL;

unordered_map a;

int main(void){
	IOS;
	int t;
	cin >> t;
	while( t-- ){
		int n;
		cin >> n;
		a.clear();
		LL ans = 0;
		for( int i = 1 ; i <= n ; i++ ){
			int x;
			cin >> x;
			if( a[x-i] ) ans += a[x-i];
			a[x-i]++;
		}
		cout << ans << endl;
		
	}
	return 0;
}

E. Arranging The Sheep

链接

https://codeforces.com/contest/1520/problem/E

题目大意

给你一个只包含‘*’和‘.’的字符串,前者代表羊,后者代表空地,询问所有羊合并到一堆的最小步数。

思路

一个数轴上有n个点,找出一个点使所有点到这个点的距离之和尽量小,这些点的中位数就是目标点。那么这道题就变成了求所有点到中位点的距离。

也可以利用前缀和后缀数组解决,遍历两边,求出每一点左右两堆羊到此的步数之和,再遍历一遍所有空点,取出步数之和的最小值。

代码
//解法1---中位数
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

const int N = 1e6+10, INF = 0x3f3f3f3f;

int dis[N];

int main(void){
	IOS;
	int t;
	cin>>t;
	while( t-- ){
		int n;
		cin>>n;
		string str;
		cin>>str;
		int cnt = 0;
		for( int i = 0 ;  i < n ; i++ )
			if( str[i] == '*' ) dis[cnt++] = i+1;
		
		int mid = cnt/2, mi = 0;
		mi = dis[mid];
		long long ans = 0;
		for( int i = 0 ; i < cnt ; i++ )
			ans += abs(dis[i]-mi) - abs(mid-i);
		cout << ans << endl;
	}
	return 0;
}
//解法2--前后缀
#include
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;

typedef long long LL;

const int N = 1e6+10;
const LL LNF = 1e18;

LL pr[N],ne[N];

int main(void){
	IOS;
	int t;
	cin >> t;
	while( t-- ){
		LL n;
		string str;
		cin >> n >> str;
		//前缀计算
		for( int i = 0 ; i < n ; i++ ){
			ne[i] = 0;
			pr[i] = 0;
		}
		LL cnt = 0;
		for( LL i = 0 ; i < n ; i++ ){
			if( i == 0 ){
				pr[i] = 0;
				cnt += ( str[i] == '*' );
				continue;
			} 
			if( str[i] == '*' ) pr[i] = pr[i-1],++cnt;
			else pr[i] = pr[i-1] + cnt;
		}
		//后缀计算
		cnt = (LL)0;
		for( LL i = n-1 ; i >= 0 ; i-- ){
			if( i == n-1 ){
				ne[i] = 0;
				cnt += ( str[i] == '*' );
				continue;
			}
			if( str[i] == '*' ) cnt++,ne[i] = ne[i+1];
			else ne[i] = ne[i+1] + cnt;
		}
		//求结果
		LL ans = LNF;
		for( LL i = 0 ; i < n ; i++ ){
			if( str[i] == '.' ){
				if( i > 0 ) ans = min(pr[i-1]+ne[i],ans);
				if( i < n-1 ) ans = min(ne[i+1]+pr[i],ans);
			}
		}
		cout << ( ans == LNF ? 0 : ans ) << endl;
	}
	return 0;
}