1. 程式人生 > >Vasya and Golden Ticket-Codeforce 512C-字首和

Vasya and Golden Ticket-Codeforce 512C-字首和

題目傳送門
題意:
給你一串數字,判斷是否能將這串數字分成和相等的幾部分。
思路:
首先將0剔除掉,因為0沒有什麼影響,只有兩種特殊情況有影響,提前判斷一下即可。然後用字首和算出所有可能區間的和,並且記錄區間的左右端點,然後排序。遍歷所有的區間,找到左端點為1的區間,然後在值相等的區間中找到可以連線的區間,知道區間的右端點等於終點。複雜度就是O(5050),O(n^2/2).
雖然沒有某些大佬們寫的簡潔,但也是我努力的成果。另外自己考慮問題不夠全面,思維還不行,需要多加練習。
官方題解做法在後面。
具體看程式碼註釋。

AC code:
#include<iostream>
#include<cstdio>
#include<vector> #include<bitset> #include<stack> #include<set> #include<queue> #include<map> #include<cmath> #include<string> #include<cstring> #include<ctime> #include<fstream> #include<cstdlib> #include<algorithm> using namespace std;
#define pii pair<int, int> #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define per(i,a,b) for(int i=a;i<=b;i++) #define rep(i,a,b) for(int i=a;i>=b;i--) #define all(x) x.begin(),x.end() #define PER(i,x) for(auto i=x.begin();i!=x.end();i++) #define PI acos(-1.0) #define INF 0x3f3f3f3f
typedef long long LL; const double eps=1.0e-5; const int maxn=100+ 10; int dx[4] = {0,0,-1,1}; int dy[4] = {1,-1,0,0}; int n = 0,size = 0; int a[maxn]; int pre_sum[maxn]; char str[maxn]; struct node{ int val; int s,e; }; node nod[maxn*maxn]; bool cmp1(node a,node b){ if(a.val != b.val){ return a.val < b.val; }else{ return a.s < b.s; } } void solve(){ int cnt = 0; per(i,0,size-1){//計算區間和 per(j,i+1,size){ nod[++cnt].val = pre_sum[j] - pre_sum[i]; nod[cnt].s = i + 1;nod[cnt].e = j; } } nod[cnt+1].val = 1e3; sort(nod + 1,nod + cnt + 1,cmp1);//排序 for(int i = 1;i <= cnt;){ if(nod[i].s != 1){//找到開始區間為1的 i++; continue; } int j = i + 1; bool flag = false; while(nod[j].val == nod[i].val){//如果等值的區間只有一個,直接continue flag = true; j++; } if(flag != true){ i = j; continue; } int temp = i; for(int k = i+1;k <= j-1;++k){ while(nod[k].s != nod[temp].e + 1 && k <= j - 1){ //找到下一個等值並且區間相接的區間(因為等值的區間可能會重疊,所以並不是檢查 //相鄰的區間,99那組測試樣例就是這樣WA的 k++; } if(k > j-1){ i = j; break; } temp = k; if(nod[temp].e == size){ printf("YES\n"); return ; } } i = j;//記得賦值,否則陷入死迴圈 } printf("NO\n"); } int main(){ #ifndef ONLINE_JUDGE freopen("a.txt","r",stdin); #endif while(~scanf("%d",&n)){ mem(pre_sum,0); scanf("%s",str); size = 0;//記錄非0數字的數量 int ct = 0; per(i,0,n-1){ if(str[i] - '0' == 0){//去掉0 ct++; continue; } a[++size] = str[i] - '0'; pre_sum[size] = pre_sum[size-1] + a[size];//計算字首和 } if(ct == n){//0的特殊情況處理 printf("YES\n"); continue; } if(ct == n-1){ printf("NO\n"); continue; } solve(); } return 0; }

官方題解做法:

AC code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<bitset>
#include<stack>
#include<set>
#include<queue>
#include<map>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
#include<fstream>
#include<cstdlib>
#include<algorithm>

using namespace std;

#define pii pair<int, int>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define all(x) x.begin(),x.end()
#define PER(i,x) for(auto i=x.begin();i!=x.end();i++)
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
typedef long long LL;
const double eps=1.0e-5;
const int maxn=100 + 10;
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int n = 0; 
char str[maxn];
void solve(){
	per(i,0,n-2){
		int sum1 = 0;
	 	per(j,0,i){
	 	 	sum1 += str[j] - '0'; 
		}
		int k = i + 1;
		while(k < n){
			int sum2 = str[k++] - '0';//不能用0作為初始值,否則與下面的while迴圈的判斷條件
			//有衝突,會陷入死迴圈,比如現在k->3,sum1->2,k+1->1,如果初始化為0,k++無法進行就會
			//死迴圈 
			//int sum2 = 0;
		  	while(k < n && sum2  + str[k] - '0'<= sum1){
		  //while(k < n && sum2 < sum1){//這種判斷條件可能會導致sum2>sum1 
		  		sum2 += str[k++] - '0';
			}
			if(sum2 != sum1){
				break;
			}
			if(sum2 == sum1 && k == n ){//將隱含條件最好寫上,防止出現 
				printf("YES\n");
				return ;
			}
		}
		
	}
	printf("NO\n");
}
int main(){
	#ifndef ONLINE_JUDGE
		//freopen("a.txt","r",stdin);
	#endif
	while(~scanf("%d",&n)){
		scanf("%s",str);
		solve();
	}
	return 0; 
}