伊格内修斯和公主IV 动态规划题解

题目描述

找一个出现大于 ( n + 1 ) / 2 (n+1)/2 (n+1)/2次数的数,保证有解。

这道题说实话不好做:卡时间,卡空间。dp应该是正解。

(dp) O ( n ) O(n) O(n)

设答案解为 x,那么可以转换思路。
将原数组变为 a [ i ] = ( a [ i ] = = x ) ? 1 : − 1 a[i] = (a[i] == x) ? 1 : -1 a[i]=(a[i]==x)?1:1,与最大子数组和的问题很像。

(1) 存在某个时候 m a x _ v a l = x max\_val = x max_val=x,即证明存在 m a x _ c n t = 0 max\_cnt = 0 max_cnt=0(就是前缀和)
数组前缀和 s u m ( n ) > = 0 sum(n) >= 0 sum(n)>=0, 假设不存在 s u m ( i ) = 0 sum(i) = 0 sum(i)=0(此时 m a x _ c n t = 0 max\_cnt = 0 max_cnt=0) 那么根据零点存在性定理,(可能有人会喷我这里说变量不是连续的,但是不可能出现 -1到1的突变)因此说不存在 s u m ( i ) < 0 sum(i) < 0 sum(i)<0, 所以保证数组从头到尾 s u m ( i ) > = 0 sum(i) >= 0 sum(i)>=0, 此时可以保证找到x。

如果存在 s u m ( i ) < 0 sum(i) < 0 sum(i)<0 ,那么同样的根据 s u m ( n ) > = 0 sum(n) >= 0 sum(n)>=0, 可以保证存在 s u m ( k ) = 0 sum(k) = 0 sum(k)=0,即有 m a x _ c n t = 0 max\_cnt = 0 max_cnt=0

(2) 设遍历到 i 的时候 m a x _ v a l = x max\_val = x max_val=x, 此时 m a x _ c n t = 0 max\_cnt = 0 max_cnt=0.
那么剩下的数有 n − i n - i ni 个, 假设剩下的 x 导致最后的 m a x _ v a l ≠ x max\_val \ne x max_val=x, 那么表明剩下的x 的个数小于 ( n − i + 1 ) / 2 (n - i + 1)/ 2 (ni+1)/2,而之前的i个数中,i出现的个数不大于 i / 2 i / 2 i/2, 因为此时在位置 i 才刚刚等于 x,加起来 x 的出现个数小于 ( n + 1 ) / 2 (n + 1) / 2 (n+1)/2, 与 x 的出现个数至少为 ( n + 1 ) / 2 (n + 1) / 2 (n+1)/2 矛盾,因此假设不成立。

所以可以保证最后的 m a x _ v a l = x max\_val = x max_val=x

(3)实现:x 不可能提前知道。所以使用动态规划的思路实现。

d p [ i ] dp[i] dp[i]为前i个数中,满足出现个数至少为 ( i + 1 ) / 2 (i + 1) / 2 (i+1)/2 的解。(解只可能有一个)
f [ i ] f[i] f[i] 为前i个数中, d p [ i ] dp[i] dp[i] 出现的个数(使用加一减一计数)。

如果 f [ i − 1 ] > 0 f[i - 1] > 0 f[i1]>0,那么 d p [ i ] = d p [ i − 1 ] , f [ i ] = f [ i − 1 ] + ( a [ i ] = = d p [ i ] ) dp[i] = dp[i - 1], f[i] = f[i - 1] + (a[i] == dp[i]) dp[i]=dp[i1],f[i]=f[i1]+(a[i]==dp[i])
如果 f [ i − 1 ] = 0 f[i - 1] = 0 f[i1]=0, 那么表明前 i − 1 i - 1 i1个数无解, d p [ i ] = a [ i ] , f [ i ] = 1 dp[i] = a[i], f[i] = 1 dp[i]=a[i],f[i]=1,开启新的阶段。

由于只使用到了前后递推,所以使用两个变量滚动数组即可: d p [ i ] = m a x _ v a l , f [ i ] = m a x _ c n t . dp[i] = max\_val, f[i] = max\_cnt. dp[i]=max_val,f[i]=max_cnt.

由于 ( 1 ) ( 2 ) (1)(2) (1)(2)的证明,可以得到最后的 m a x _ v a l = x max\_val = x max_val=x

C++ 代码

#include <bits/stdc++.h>
#pragma GCC optimize(2) 
using namespace std;

int n;

int main() {
    
    
	while (~scanf("%d", &n)) {
    
    
		int max_val = 0, max_cnt = 0;
		for (int i = 0; i < n; i++) {
    
    
			int temp;
			scanf("%d", &temp);
			if (max_cnt == 0) {
    
    
				max_cnt = 1;
				max_val = temp;
			} else {
    
    
				max_cnt += (temp == max_val ? 1 : -1);
			}
		}
		cout << max_val << endl;
	}
}

猜你喜欢

转载自blog.csdn.net/m0_51156601/article/details/126141195