URAL 1310. ACM Diagnostics


题意,给定数字L,M,K,N 。

L 个数字,每个数字的取值范围是 1 , 2 , ... , M 。

在符合上述条件的所有组合中,L个数字之和为K的倍数的组合 称为一个状态。 

将所有可能的状态按字典序排序,编号从0开始。

求编号为 N 的那个状态。

L=100,M=50 ; K=1  的时候,每种组合都是状态,总共 50的100次方种组合。

所以 N 的上限是 50 的100次方 -1。

于是要写一个大数类。只需要  加,减,比较 操作。

 然后 F[ i ] [ j ] 表示,i 个数,数字的和除以K的余数为 j  的情况种数。

然后从最高位开始一个一个确定数字就行了。


#define FOR(i,n) for(long long (i)=1;(i)<=(n);(i)++)
#define For(i,n) for(long long (i)=0;(i)<(n);(i)++)
using namespace std;
struct Int{
	char a[1000];
	int len;
	Int(int k){*this=k;}
	Int(){*this=0;}
	void operator =(int k){
		if(!k){len=1;a[0]=0;return;}
		len=0;
		while(k) a[len++]=k%10,k/=10;
	}
	void operator =(string k){
		len=k.length();
		for(int i=0;i<len;i++) {
			a[i]=k[len-i-1]-48;
		}
	}
	Int operator +(Int &B){
		Int C;C.len=len>B.len?len:B.len;
		for(int i=len;i<C.len;i++) a[i]=0;
		for(int i=B.len;i<C.len;i++)B.a[i]=0;
		int d=0;
		for(int i=0;i<C.len;i++){
			C.a[i]=a[i]+B.a[i]+d;
			d=C.a[i]/10;
			C.a[i]%=10;
		}
		if(d) C.a[C.len++]=d;
		return C;
	}
	Int operator +=(Int B){
		*this=*this+B;
		return *this;
	}
	Int operator -(Int &B){
		Int C;C.len=len;
		for(int i=B.len;i<C.len;i++)B.a[i]=0;
		int d=0;
		for(int i=0;i<C.len;i++){
			C.a[i]=a[i]-B.a[i]-d;
			d=0;
			while(C.a[i]<0) d++,C.a[i]+=10;
		}
		while(C.len>0&&!C.a[C.len-1]) C.len--;
		if(C.len==0) C=0;
		return C;
	}
	bool operator>=(Int B){
		if(len>B.len) return 1;
		if(len<B.len) return 0;
		for(int i=len-1;i>=0;i--){
			if(a[i]>B.a[i]) return 1;
			if(a[i]<B.a[i]) return 0;
		}
		return 1;
	}
	void show(){
		for(int i=len-1;i>=0;i--) printf("%d",a[i]);
	}
};
Int f[101][50];
int s[101];
int L,M,K;
string N;Int NN;
void F(Int k){
	int CurR=0;
	FOR(i,L){
		s[i]=1;
		while(k>=f[L-i][(K-(CurR+s[i])%K)%K]){
			k=k-f[L-i][(K-(CurR+s[i])%K)%K];
			s[i]++;
			if(s[i]==M) break;
		}
		CurR+=s[i];
		CurR%=K;
	}
	FOR(i,L){
		printf("%d",s[i]);
		if(i==L) printf("\n");
		else printf(" ");
	}	
}
int main(void)
{
	while(cin>>L>>M>>K>>N){
		For(i,101) For(j,50) f[i][j]=0;
		f[0][0]=1;
		For(i,L){
			For(j,K){
				FOR(k,M){
					f[i+1][(j+k)%K]+=f[i][j];
				}
			}
		}
		NN=N;//string 转换到 Int
		F(NN);//根据编号确定组合。
	}
return 0;
}








 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值