F - Valid payments(进制&dp)

思路

Z = Y − X Z=Y-X Z=YX

X = ∑ i = 1 n x i a i , Y = ∑ i − 1 n y i a i , Z = ∑ i = 1 n z i a i X=\sum\limits_{i=1}^nx_ia_i,Y=\sum\limits_{i-1}^n y_ia_i,Z=\sum\limits_{i=1}^n z_ia_i X=i=1nxiai,Y=i1nyiai,Z=i=1nziai

依题意 y i , z i y_i,z_i yi,zi不能同时 > 0 >0 >0

注意到 X X X是确定的,可以被唯一表示。

所以我们来考虑 Z Z Z的组成情况,因为 Z Z Z确定了, Y Y Y就确定了。

具体来说:当确定 z i z_i zi和该位是否进位, y i y_i yi就确定了。

因为 z i + w + x i = y i z_i+w+x_i=y_i zi+w+xi=yi w w w表示第 i − 1 i-1 i1位是否进位,进位为 1 1 1,否则为 0 0 0

Y Y Y的方案对应 Z Z Z的方案。

d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]表示第 i i i位不进位和进位的方案数。

1.当 z i z_i zi对应的第 i i i位不进位时,因为 x i + 1 < m x i + 1 x_{i+1}<mx_{i+1} xi+1<mxi+1,所以当 z i + 1 = 0 z_{i+1}=0 zi+1=0 即第 i + 1 i+1 i+1位也可以不进位。

即: d p [ i + 1 ] [ 0 ] = d p [ i ] [ 0 ] dp[i+1][0]=dp[i][0] dp[i+1][0]=dp[i][0]


2.类似地,有 d p [ i + 1 ] [ 1 ] + = d p [ i ] [ 1 ] dp[i+1][1]+=dp[i][1] dp[i+1][1]+=dp[i][1]


3.当 x i + 1 ≠ 0 x_{i+1}\ne 0 xi+1=0时,显然第 i i i位不进位,第 i + 1 i+1 i+1位也可以 进位,只要 z i = m x i + 1 − x i + 1 z_i=mx_{i+1}-x_{i+1} zi=mxi+1xi+1,因为 z i + 1 < m x i + 1 z_{i+1}<mx_{i+1} zi+1<mxi+1

即: i f ( x x [ i + 1 ] )   d p [ i + 1 ] [ 1 ] = d p [ i ] [ 0 ] if(xx[i+1])\ dp[i+1][1]=dp[i][0] if(xx[i+1]) dp[i+1][1]=dp[i][0]


4.类似地,有 i f ( x x [ i + 1 ] + 1 ! = m x [ i + 1 ] )   d p [ i + 1 ] [ 0 ] + = d p [ i ] [ 1 ] if(xx[i+1]+1!=mx[i+1]) \ dp[i+1][0]+=dp[i][1] if(xx[i+1]+1!=mx[i+1]) dp[i+1][0]+=dp[i][1]

因为 m x n mx_{n} mxn不存在,所以第 n n n位不可能进位,所以 a n s = d p [ n ] [ 0 ] ans=dp[n][0] ans=dp[n][0]

时间复杂度: O ( n ) O(n) O(n)


代码

// Problem: F - Valid payments
// Contest: AtCoder - AtCoder Beginner Contest 182
// URL: https://atcoder.jp/contests/abc182/tasks/abc182_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-03-05 22:23:55
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=55,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
ll a[N],dp[N][2],xx[N],mx[N];
int main(){
	int n;ll x;scanf("%d%lld",&n,&x);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<n;i++) mx[i]=a[i+1]/a[i];
	ll t= x;
	for(int i=n;i;i--){
		xx[i]=t/a[i]; //xx[i]<mx[i]
		t%=a[i];
	}
	dp[1][0]=1;
	if(xx[1]) dp[1][1]=1;
	for(int i=1;i<n;i++){
		dp[i+1][0]=dp[i][0];
		if(xx[i+1]) dp[i+1][1]=dp[i][0];
		dp[i+1][1]+=dp[i][1];
		if(xx[i+1]+1!=mx[i+1]) dp[i+1][0]+=dp[i][1];
	} 
	printf("%lld\n",dp[n][0]);
	return 0;
}