ybt1195 判斷整除(自己立的flag,跪着也要打完)


ybt1195 判斷整除

【題目描述】

一個給定的正整數序列,在每個數之前都插入+號或−號后計算它們的和。比如序列:1、2、4共有8種可能的序列:

(+1) + (+2) + (+4) = 7
(+1) + (+2) + (-4) = -1
(+1) + (-2) + (+4) = 3
(+1) + (-2) + (-4) = -5
(-1) + (+2) + (+4) = 5
(-1) + (+2) + (-4) = -3
(-1) + (-2) + (+4) = 1
(-1) + (-2) + (-4) = -7

所有結果中至少有一個可被整數k整除,我們則稱此正整數序列可被k整除。例如上述序列可以被3、5、7整除,而不能被2、4、6、8……整除。注意:0、−3、−6、−9……都可以認為是3的倍數。

【輸入】

輸入的第一行包含兩個數:N(2<N<10000)和k(2<k<100),其中N代表一共有N個數,k代表被除數。第二行給出序列中的N個整數,這些整數的取值范圍都0到10000之間(可能重復)。

【輸出】

如果此正整數序列可被kk整除,則輸出YES,否則輸出NO。(注意:都是大寫字母)

【輸入樣例】

3 2 
1 2 4 

【輸出樣例】

NO

【題解】

首先,先看題干中的例子,可以看出,組合后的結果的符號與整除於否無關,所以就不用考慮一半的情況。

再者,序列中的數字,能影響答案的,並不是整個數,而是它模k的值罷了,所以對數據進行處理,縮小數據。

	for(int i=1;i<=n;i++) {
		cin>>tmp;
		tmp%=k;//預處理
		a[i]=tmp;
	}

接下來,就到了簡化問題的時間

由1,2,4來分析,如果從1開始加入序列,那么1可以被1整除

接下來2加入,這樣就有1和3(結果只取絕對值)兩個數可以整除

再接下來是4,這樣子1,3,5,7就都符合整除規則了。

所以我們就想到(題解就說道)

可以從頭開始,一個一個來(讓元素入列)

因為元素越多,組合方式是以指數級爆炸的,又因為如此多的組合的結果有大量重復,所以說就想到(題解說)可以以k為數組的第二維,只要枚舉余數,就可以將復雜度控制到可控范圍。

那么,就可以用bool變量fi,j表示前i個數是否可以被j整除(1可以,0不可以)

如果要轉移到fi,j的狀態,那么就要在前i-1個數已經入列的基礎上再加第i個數,而第i個數又只有正和負兩種情況所以便只考慮是由加第i個數和減第i個數就好了。

要想加ai得到余數為j的情況,那么前i-1個數必須滿足余數可以為j-ai

反之,若減ai得到余數可以為j,那么前i-1個數必須滿足余數可以為j+ai

所以,要想ai入列后,余數為j,那么上述兩個條件滿足一個就好。

列出方程:fi,j=fi-1,j-ai||fi-1,j+ai

(不過為了防止爆數組,要控制j+-ai的數據在k的范圍內,所以要+k然后%k)

邊界條件:f0,0=1(0個元素,結果為零,所以不管k為多少,余數都為零)

代碼打出來是這樣的:

#include<iostream>
#include<cstring>
using namespace std;
int a[10005],n,k,tmp;
bool f[10005][105];
int main() {
	cin>>n>>k;
	memset(a,0,sizeof(a));
	for(int i=1;i<=n;i++) {
		cin>>tmp;
		tmp%=k;
		a[i]=tmp;
	}
	f[0][0]=1;//邊界
	for(int i=1;i<=n;i++) {
		for(int j=0;j<k;j++){
			f[i][j]=(f[i-1][(j-a[i]+k)%k]||f[i-1][(j+a[i]+k)%k]);//遞推
		}
	}
	if(f[n][0]){
		cout<<"YES"<<endl;
	}
	else{
		cout<<"NO"<<endl;
	}
	return 0;
}

Ps:因為本題轉移時調用的數組的第二維較為隨機,所以就不會懶得滾動數組了······

感謝題解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM