清北-Day5-R2-divide

题目描述
问是否可以将一个仅由0~9组成的字符串划分成两个或两个以上部分,使得每一部分的数字总和相等。

输入
输入文件名为 \(divide.in\)
多组数据,第一行一个数\(n\),表示数据组数
接下来\(n\)行,每行包含一个字符串

输出
输出文件名为\(divide.out\)
输出n行,每行为 \(’YES’\) 或者 \(’NO’\) ,表示是否存在题目要求的划分方案。

样例输入

3
1248
2680
54174760

样例输出

NO
YES
YES

提示
【数据说明】
对于50%的数据,$ 2 \le Length \le 100 $

对于100%的数据,$ 1 \le n \le 5 , 2 \le Length \le 10^5 $

啊,这个题,我一直以为挺难的,是个DP,结果后来发现枚举就行.....当时心里那个mmp
枚举就简单了啊
我是枚举分成多少段,然后在原数列中去 $ check $ 是否可行,至于每一段的和,直接用总和作除法就行了
当然,如果说根本无法分成当前枚举到的段数,那么直接 $ continue $
否则就一直凑就行了,每一段的和我是维护前缀和然后 \(\Theta(1)\) 求的,这个题总体比较简单,毕竟是 CF Div2 的 C题改过来的,也不是很难
至于代码.....如下吧:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define LL long long

const int N = 1e5 + 5 ;
LL T , sum[N] ;
char s[N] ;
bool f ;

inline LL read(){
	LL x = 0 , f = 1 ;char ch = getchar ();
	while ( ch < '0' || ch > '9' ){if ( ch == '-' ) f = - 1 ;ch = getchar ();}
	while ( ch >= '0' && ch <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( ch ^ 48 ) ;ch = getchar () ; }
	return f * x ;
}

int main(){
	T = read (); sum[0] = 0 ;
	while ( T -- ){
		scanf ("%s" , s + 1 ) ; f = false ;
		register int L = strlen ( s + 1 ) ;
		for ( int i = 1 ; i <= L ; ++ i)
			sum [i] = sum [ i - 1 ] + s[i] - '0' ;
		if ( sum[L] == 0 ) { puts("YES") ; continue ;}
		for ( int i = 2 ; i <= sum[L] ; ++ i){ // 枚举分成多少段 
			if ( sum[L] % i ) continue ; // 连整除都做不到还要你作甚 
			register int tmp = sum[L] / i , k = 0 ; // tmp是每段的和 , k是当前是第几段
			if ( tmp == sum[L] ) continue ;
			for (int j = 1 ; j <= L ; ++ j){
				if ( sum[j] - k * tmp == tmp ) ++ k ; // 如果当前枚举到的子段和恰好与枚举的和相等,继续推进 
				else if ( sum[j] - k * tmp > tmp ) break ;// 否则,如果比当前枚举的和大,那么直接跳过,不鸟他 
			}
			if ( k == i ) { f = true ; break ;}
		}
		if ( f ) puts ("YES");
		else puts ("NO");
	}
	return 0;
}
posted @ 2018-11-05 11:23  Phecda  阅读(171)  评论(0编辑  收藏  举报

Contact with me