poj1745 - Divisibility

1254 ワード

NとKを与えて、次に、正負にかかわらず、N個の整数を与え、このN個の数のうち、2個の数の間に(すなわちN-1の位置)プラス記号またはマイナス記号を追加し、演算した値をKに対して余剰を取り、余剰が0に等しい場合はDivisibleを出力し、そうでなければNot divisibleを出力して問題を解く構想:4 7 17 5-21 15を例にまず1つの数を取り、言うまでもなく、最初の数の前に記号を付けないのが本体であり、それ自体が直接Kに余剰を取ると、17を取るときに余剰が2になる個5,(2+5)対7取余が0(2-5)対7取余が4(取余の負数を正)では、前の2つの数に余剰が0と4もう一つの-21(0+21)対7取余が0(0-21)対7取余が0(0-21)対7取余が0(4+21)対7取余が4(4-21)対7取余が4もう一つ-15と同様(0+15)%7=1(0-15)%7=6(4+15)%7=5(4-15)%7=3同理は法則を見つけることができ、dp[i][j]を前のi個の数の剰余を定義するのはjが成立するかどうか、1が成立するかどうか、0が成立しないならば、dp[N][0]が1であれば、1つの数を構成してKに剰余を0にすることができ、dpを0に初期化することができる
そしてdp[1][a[1]%k]=1 for i=2 to N do for j=0 to K do if(dp[i-1][j])dp[i][j+a[i]%k]=1;  dp[i][(j - a[i])%k] = 1;  if end for end for end
#include 
using namespace std;
#define MAXN 10001

int dp[MAXN][101];

int posmod(int n,int k){		    
	n = n % k;
	while(n < 0) n+=k;
	return n;
}

int main(){
	int n,k;
	int i ,j ,tmp;
	int a[MAXN];
	while(cin>>n>>k){
		memset(dp,0,sizeof(dp));
		for(i = 1;i <= n;i++) cin>>a[i];
		dp[1][posmod(a[1],k)] = 1;
		for(i = 2;i <= n;i++){
			for(j = 0;j < k;j++){
				if(dp[i - 1][j]){
					dp[i][posmod(j + a[i],k)] = 1;
					dp[i][posmod(j - a[i],k)] = 1;
				}
			}
		}
		if(dp[n][0]){
			cout<