AtCoder Beginner Contest 044(ABCD)题解

AtCoder Beginner Contest 044(ABCD)题解

传送门

A - Tak and Hotels (ABC Edit)

思路:显然讨论一下 k k k的范围即可。

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

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
int main(){
	int n,k,x,y;
	cin>>n>>k>>x>>y;
	int ans=0;
	if(n<=k) ans+=n*x;
	else if(n>k) ans+=k*x+(n-k)*y;
	cout<<ans;
	return 0;
}

B - Beautiful Strings

思路:按照题意模拟,特判 26 26 26个字母即可。

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

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
int a[26];
int main(){
	string s;
	cin>>s;
	for(int i=0;i<s.size();i++)
		a[s[i]-'a']++;
	int ok=1;
	//for(int i=0;i<26;i++) printf("%d %d\n",i,a[i]);
	for(int i=0;i<26;i++)
		if(a[i]&1) {
			ok=0;
			break;
		}
		puts(ok?"Yes":"No");
	return 0;
}

C - Tak and Cards

思路:背包问题。看着数据范围,妥妥的 d p dp dp

我一开始设的是 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前 i i i个数选 j j j个数和为 k k k的方案数。

显然有状态转移方程: d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j − 1 ] [ k − a [ i ] ] , ( k ≥ a [ i ] ) d p [ i ] [ j ] [ k ] + = d p [ i ] [ j − 1 ] [ k ] dp[i][j][k]=dp[i-1][j-1][k-a[i]],(k\geq a[i])\\dp[i][j][k]+=dp[i][j-1][k] dp[i][j][k]=dp[i1][j1][ka[i]],(ka[i])dp[i][j][k]+=dp[i][j1][k]

然后三重循环递推即可。

时间复杂度: O ( n 3 ) O(n^3) O(n3)

空间复杂度: O ( n 2 ) O(n^2) O(n2)

后来 A C AC AC了发现,这不就是背包的裸题吗。

显然可以进行优化第一维,只不过第二重和第三重循环改成倒序遍历以保证是 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i1][j1]的状态,不然顺序遍历会影响该状态。

空间复杂度: O ( n 2 ) O(n^2) O(n2)

p s : ps: ps:看来还是背包做少了。

#include
using namespace std;
typedef long long ll;
const int N=50+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
int a[N];
ll dp[N][N][3000],pre[1005];
int main(){
	int n,k;
	cin>>n>>k;
	ll  ans=0,sum=0; 
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
		pre[i]=pre[i-1]+a[i];
	}
	for(int i=0;i<=n;i++) dp[i][0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++)
		for(int k=1;k<=pre[i];k++){
			if(k>=a[i])
			dp[i][j][k]+=dp[i-1][j-1][k-a[i]];
			dp[i][j][k]+=dp[i-1][j][k];
			//printf("dp[%d][%d][%d]=%d\n",i,j,k,dp[i][j][k]);
		}
	}
	for(int i=1;i<=n;i++)
			ans+=dp[n][i][i*k];
		printf("%lld\n",ans);
	return 0;
}

空间优化后:

#include
using namespace std;
typedef long long ll;
const int N=50+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
int a[N],n,k;
ll dp[N][3000],ans;
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	 dp[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=i;j>=1;j--)
		for(int k=2500;k>=a[i];k--) dp[j][k]+=dp[j-1][k-a[i]];
	for(int i=1;i<=n;i++) ans+=dp[i][i*k];
		printf("%lld\n",ans);
	return 0;
}

D - Digit Sum

思路:第一眼看数据范围 1 e 11 1e11 1e11,可以想到是 O ( n ) O(\sqrt{n}) O(n )左右的算法。

后来看题解是发现,利用数论知识分类讨论。

显然题意是要求我们将 n n n转化为 b b b进制然后对每位求和看是否等于 s s s,找到最小的 b b b

即: a 0 × b 0 + a 1 × b 1 ⋯ + a k × b k = n a_0\times b^0+a_1\times b^1\dots+a_k\times b^k=n a0×b0+a1×b1+ak×bk=n

∑ i = 0 k a i = s \sum\limits_{i=0}^ka_i=s i=0kai=s

显然当 k ≥ 2 k\geq 2 k2时,有 b 2 ≤ n → b ≤ n b^2\leq n\rightarrow b\leq\sqrt{n} b2nbn

对于这部分直接暴力从小到大枚举即可。时间复杂度: O ( n l o g b n ) O(\sqrt{n}log_b\sqrt{n}) O(n logbn )

对于 b > n b>\sqrt{n} b>n 部分,显然 k k k最多是 1 1 1.

则有方程: a 0 + a 1 × b = n a 0 + a 1 = s → a 1 × ( b − 1 ) = n − s → b = n − s a 1 + 1 a_0+a_1\times b=n\\a_0+a_1=s\\ \rightarrow a_1\times(b-1)=n-s\\ \rightarrow b=\dfrac{n-s}{a_1}+1 a0+a1×b=na0+a1=sa1×(b1)=nsb=a1ns+1

显然 a 1 < ( b − 1 ) , b > n , a 1 ≤ ( n − s ) a_1<(b-1),b>\sqrt{n},a_1\leq\sqrt{(n-s)} a1<(b1),b>n ,a1(ns)

所以我们从大到小枚举 a 1 a_1 a1即可,等价于从小到大枚举 b b b

貌似 a 1 a_1 a1的范围还可以再缩小,但是没必要了,够了。

总时间复杂度: O ( n l o g b n + n − s l o g b a 1 ) O(\sqrt{n}log_b\sqrt{n}+\sqrt{n-s}log_b a_1) O(n logbn +ns logba1)

#include
using namespace std;
typedef long long ll;
const int N=50+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
ll x;
ll fun(ll b){
	ll sum=0;
	while(x>=b){
		sum+=x%b;
		x/=b;
	}
	sum+=x;
	return sum;
}
int main(){
	ll n,s;
	cin>>n>>s;
	if(s==n) printf("%lld\n",n+1),exit(0);
	if(s>n) return puts("-1"),0;
	for(ll i=2;i*i<=n;i++){
		x=n;
		if(fun(i)==s){
			printf("%lld\n",i);
			return 0;
		}
	}
	for(ll i=sqrt(n-s);i>=1;i--){
		x=n;
		 if((n-s)%i==0){
		 	ll b=(n-s)/i+1;
		 	if(b>=2&&fun(b)==s) {
			 printf("%lld\n", b);
			 return 0;
			}
		 }
	}
	puts("-1");
	return 0;
}

你可能感兴趣的:(Atcoder题解)