Codeforces Round #627 (Div. 3)

这次比赛还可以,但是E题很不舒服。。。感觉E题题意.....什么玩意。。欺负英语学渣吗。。。被逼无奈学英语?
A
题意:
你有两个操作,
1、将某一列的高度加2,
2、在所有 a i a_i ai都大于0的情况下,将所有 a i a_i ai减一。
问你是否能够将所有列都变为0。
思路:
看所有列的高度是否与2同余。若同余则可以变为同一高度,最后都可以变为0。
B
题意:
问是否有一个长度大于3的回文子序列,暴力完事,枚举每个位置。

int a[N];
int main(){
	int t = read();
	while(t--){
		int n = read();
		rep(i,1,n) a[i] = read();
		bool r = 0;
		rep(i,1,n-2){
			r = 0;
			rep(j,i+2,n){
				if(a[i] == a[j]){
					r = 1;break;
				}
			}
			if(r == 1) break;
		}
		if(r) puts("YES");
		else puts("NO");
	}
}

C
题意:
青蛙要从0位置跳到 n + 1 n+1 n+1去, 1 − n 1-n 1n每个位置会有两种字符: L , R L,R L,R。在 L L L字符只能往左跳, R R R字符处只能往右跳。你有一个最大距离 d d d,你每次跳的距离为 [ 1 , d ] [1,d] [1,d],让你输出你可以恰好到达 n + 1 n+1 n+1处的最小的 d d d
思路:
首先从0处也只能往右跳,所以我们不妨设0处的字符也为 R R R。那么很显然,我们只能在字符 R R R处往右跳才能到达 n + 1 n+1 n+1。我们如何找这个最小的 d d d呢, d d d最小的情况肯定是不停的在 R R R上跳啊,所以我们只需要找相邻两个 R R R之间的最大距离,但是别忘了终点 n + 1 n+1 n+1,因为最后一步肯定是从某个 R R R跳到它,为了方便起见,我们设 n + 1 n+1 n+1处也为 R R R。扫一遍即可。

char s[N];
int main(){
	int t = read();
	while(t --){
		scanf("%s",s+1);
		s[0] = 'R';
		int l = strlen(s+1);
		s[l+1] = 'R';
		int op = 0;
		int M = -1;
		rep(i,1,l+1){
			if(s[i] == 'R'){
				M = max(M,i-op);
				op = i;
			}
		}
		cout <<M<<endl;
	}
}

D
题意:
n n n个数,两个序列, a 1 , a 2 . . . . a n a_1,a_2....a_n a1,a2....an b 1 , b 2 . . . . b n b_1,b_2....b_n b1,b2....bn
现在让你求 i < j ii<j a i + a j > b i + b j a_i+a_j>b_i+b_j ai+aj>bi+bj的对数。
思路:
读这个题时,想上厕所。。。所以读的急,以为能排序。。。后来又读了遍,发现难度没这么大。。不过,如果可以排序,那怎么做呢?

此题中的式子可以移下项:
a i + a j > b i + b j a_i+a_j>b_i+b_j ai+aj>bi+bj

= ( a i − b i ) + ( a j − b j ) > 0 =(a_i-b_i)+(a_j-b_j)>0 =(aibi)+(ajbj)>0

我们令 c i = a i − b i c_i=a_i-b_i ci=aibi 这个题就转化为 c i + c j > 0 c_i+c_j>0 ci+cj>0有多少对。排序后二分查找。

int a[N];
int b[N];
int main(){
	int n = read();
	rep(i,1,n) a[i] = read();
	rep(i,1,n) b[i] = read();
	rep(i,1,n) a[i] -= b[i];
	sort(a+1,a+n+1);
	ll sum = 0;
	rep(i,1,n-1){
		int l = i+1,r = n+1;
		while(l < r){
			int mid = l + r >> 1;
			if(a[mid] + a[i] > 0) r = mid;
			else l = mid + 1;
		}
		if(r != n +1) sum += (n - r + 1);
	}
	cout<<sum;
}

E
题意:
这个题意转换后是,一天有 h h h个小时,然后你从0点开始,不断睡觉,第 i i i的睡眠时间为 a i a_i ai,如果你睡眠的时刻刚好在 [ l , r ] [l,r] [l,r]这个区间内,那么这个是好的。你可以选择睡 a i a_i ai或者 a i − 1 a_i-1 ai1个小时,让你输出最多有多少个好的
思路:
我憨批了。。。调很久发现是初始化的问题。
这个题目当时没做出来很不应该,以前做过这种类型的题,类似于被背包的转移。设 d p [ i ] [ j ] dp[i][j] dp[i][j]代表前 i i i个物品中,当前时刻为 j j j的最多好的数量。
那么转移方程是
d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ ( j − ( a i ) + h ) % h ] } dp[i][j] =max \{dp[i-1][(j-(a_i)+h)\%h]\} dp[i][j]=max{dp[i1][(j(ai)+h)%h]}
或者 d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ ( j − ( a i − 1 ) + h ) % h ] } dp[i][j]=max\{dp[i-1][(j-(a_i-1)+h)\%h ]\} dp[i][j]=max{dp[i1][(j(ai1)+h)%h]}
并且如果 j > = l & & j < = r j>=l\&\&j<=r j>=l&&j<=r记得加1就好。

int a[N];
int dp[3001][3001];
int main(){
    int n = read(),h = read(),l = read(),r = read();
    rep(i,1,n) a[i] = read();
    memset(dp,-1,sizeof dp);
    dp[0][0] = 0;
    int M = 0;
    rep(i,1,n){     
        for(int j = 0;j < h;++j){
            int d = (j - a[i] + h ) % h;
            if(dp[i-1][d]!=-1){
                dp[i][j] = max(dp[i][j],dp[i-1][d]);
            }
            d = (j-(a[i]-1)+h)%h;
            if(dp[i-1][d]!=-1){
                dp[i][j] = max(dp[i][j],dp[i-1][d]);
            }
            if(dp[i][j]!=-1&&j>=l&&j<=r) dp[i][j] ++;
            M = max(M,dp[i][j]);
        }
    }
    cout << M;
}

F

你可能感兴趣的:(Contest)