2020-07-23 题解

写在前面

自闭ing...

题目

A.玛雅文字

刚开始打了一个非常zz的代码,具体多zz看代码就知道了:

//zz般的代码
#include <bits/stdc++.h>
using namespace std ;
const long long BASE = 13331 ;
const int MAXS = 3000000 + 5 , MAXT = 3000 + 5 ;
int n , m ;
long long res , ret ;
int ans ;
char s[ MAXS ] , t[ MAXT ] ;
inline long long hsh ( char ch ) {
	return ( long long ) ch * BASE ;
}
signed main () {
	freopen ( "mayan.in" , "r" , stdin ) ;
	freopen ( "mayan.out" , "w" , stdout ) ;
	scanf ( "%d%d" , &m , &n ) ;
	scanf ( "%s%s" , t + 1 , s + 1 ) ;
	int l = 1 , r = m ;
	for ( int i = l ; i <= r ; i ++ ) {
		res += hsh ( s[ i ] ) ;
		ret += hsh ( t[ i ] ) ;
	}
	if ( res == ret ) ans ++ ;
	while ( r <= n ) {
		l ++ ; r ++ ;
		res -= hsh ( s[ l - 1 ] ) ;
		res += hsh ( s[ r ] ) ;
		if ( res == ret ) ans ++ ;
//		cout << l << " " << r << " " << res << " " << ret << endl ;
	}
	printf ( "%d\n" , ans ) ;
	return 0 ;
} 

对此代码进行分析,发现\(hash\)的碰撞率\(\approx 1\)

但是我竟然还有20分...

于是打了一个正差的\(hash\)(在复杂化的道路上一去不复返...)

#include <bits/stdc++.h>
using namespace std ;
const int MAXS = 3000000 + 5 , MAXT = 3000 + 5 ;
int n , m ;
long long res , ret ;
int ans ;
char s[ MAXS ] , t[ MAXT ] ;
long long base[ 130 ] ;
inline long long hsh ( char ch ) {
	return ( long long ) ch * base[ ch ] ;
}
signed main () {
	freopen ( "mayan.in" , "r" , stdin ) ;
	freopen ( "mayan.out" , "w" , stdout ) ;
	scanf ( "%d%d" , &m , &n ) ;
	scanf ( "%s%s" , t + 1 , s + 1 ) ;
	int l = 1 , r = m ;
	base[ 'a' ] = 3001 ;
	for ( int i = 1 ; i <= 25 ; i ++ )
		base[ i + 'a' ] = base[ i + 'a' - 1 ] * 3001 ;
	base[ 'A' ] = 3001 * 28 ;
	for ( int i = 1 ; i <= 25 ; i ++ )
		base[ i + 'A' ] = base[ i + 'A' - 1 ] * 3001 ;
	for ( int i = l ; i <= r ; i ++ ) {
		res += hsh ( s[ i ] ) ;
		ret += hsh ( t[ i ] ) ;
	}
	if ( res == ret ) ans ++ ;
	while ( r <= n ) {
		l ++ ; r ++ ;
		res -= hsh ( s[ l - 1 ] ) ;
		res += hsh ( s[ r ] ) ;
		if ( res == ret ) ans ++ ;
//		cout << l << " " << r << " " << res << " " << ret << endl ;
	}
	printf ( "%d\n" , ans ) ;
	return 0 ;
} 

唉,第一题TMD搞死我了(话说第一题我想那么复杂干嘛)

以后写\(hash\)还是要悠着点

B.奇怪的字符串

观察可得,所谓的奇怪字符串要么是全都是同一个字符,要么就是两串相同的字符拼接起来的。

eg.aaaaaaa bbb aabbbbb bbba ccccaaaaaaa

那么就比较简单了

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std ;
#define int long long
const int MAXN = 2e5 + 5 , MAXM = 35 ;
int n , res , p[ MAXM ] ;
int tot , len[ MAXN ] , l[ MAXN ] ;
char ch[ MAXN ] ;
vector < pair < int , int > > v[ MAXM ][ MAXM ] ;
signed main () {
	scanf ( "%s" , ch + 1 ) ;
	n = strlen ( ch + 1 ) ;
	for ( int i = 1 ; i <= n ; i ++ ) ch[ i ] -= 'a' ;
	tot = 1 ; l[ 1 ] = 1 ;
	for ( int i = 2 ; i <= n + 1 ; i ++ ) {
		if ( ch[ i ] != ch[ l[ tot ] ] || i > n ) {
			len[ tot ] = i - l[ tot ] ;
			p[ ch[ l[ tot ] ] ] = max ( p[ ch[ l[ tot ] ] ] , len[ tot ] ) ;
			l[ ++ tot ] = i ;
		}
	}
	for ( int i = 0 ; i < 26 ; i ++ ) res += p[ i ] ;
	for ( int i = 2 ; i < tot ; i ++ ) v[ ch[ l[ i - 1 ] ] ][ ch[ l[ i ] ] ].push_back ( make_pair ( len[ i - 1 ] , len[ i ] ) ) ;
	for ( int i = 0 ; i < 26 ; i ++ )
		for ( int j = 0 ; j < 26 ; j ++ ) {
			int mx = 0 , tot = v[ i ][ j ].size () ;
			if ( !tot ) continue ;
			sort ( v[ i ][ j ].begin () , v[ i ][ j ].end () ) ;
			for ( int k = tot - 1 ; k >= 0 ; k -- ) {
				mx = max ( mx , v[ i ][ j ][ k ].se ) ;
				if ( k > 0 ) res += mx * ( v[ i ][ j ][ k ].fi - v[ i ][ j ][ k - 1 ].fi ) ;
				else res += mx * v[ i ][ j ][ k ].fi ;
			}
		}
	printf( "%lld\n" , res ) ;
	return 0 ;
}

C.超级跳棋

对于一个数 \(x\) ,应该有以下方案

T x T||x T T||T T x (T需要有两个以上)
S T x||S x T||x S T (S,T无大小关系)
x T x||x x T||T x x (x需要有两个以上)
x x x (x需要有3个以上)
#include <bits/stdc++.h>
#define int long long
using namespace std ;
const int MAXN = 100000 + 5 ;
int n , k , tot ;
long long ans ;
int a[ MAXN ] , c[ MAXN ] , w[ MAXN ] ;
inline int read () {
	int tot = 0 , f = 1 ; char c = getchar () ;
	while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -1 ; c = getchar () ; }
	while ( c >= '0' && c <= '9' ) { tot = tot * 10 + c - '0' ; c = getchar () ; }
	return tot * f ;
}
signed main () {
	n = read () ; k = read () ;
	for ( int i = 1 ; i <= n ; i ++ )
		a[ i ] = read () ;
	sort ( a + 1 , a + 1 + n ) ;
	c[ tot = 1 ] = 1 ;
	for ( int i = 2 ; i <= n ; i ++ ) {
		if ( a[ i ] == a[ i - 1 ] ) c[ tot ] ++ ;
		else a[ ++ tot ] = a[ i ] , c[ tot ] = 1 ;
	}
	for ( int i = 1 ; i <= tot ; i ++ ) {
		w[ i ] = lower_bound ( a + 1 , a + i , a[ i ] / k + ( a[ i ] % k != 0 ) ) - a ;
		if ( i - w[ i ] >= 2 ) ans += ( i - w[ i ] ) * ( i - w[ i ] - 1 ) / 2 * 6 ;
	}
	for ( int i = 1 ; i <= tot ; i ++ ) {
		if ( c[ i ] < 2 ) continue ;
		if ( i - w[ i ] >= 1 ) ans += ( i - w[ i ] ) * 3 ;
		int x = upper_bound ( a + i , a + tot + 1 , a[ i ] * k ) - a - 1 ;
		x = min ( x , tot ) ;
		if ( x - i >= 1 ) ans += ( x - i ) * 3 ;
	}
	for ( int i = 1 ; i <= n ; i ++ )
		if ( c[ i ] >= 3 ) ans ++ ;
	printf ( "%lld\n" , ans ) ;
	return 0 ;
}

posted @ 2020-07-23 15:41  hulean  阅读(210)  评论(0编辑  收藏  举报