B题:Beautiful Strings
给定一个只包含小写字母的字符串,询问是每个字母出现的次数都是偶数次
Solution
按照题意模拟即可,在这里可以直接使用unordered_map记录每个字母出现次数
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
string s; cin >> s;
unordered_map<char, int>a;
for (auto x : s)
a[x]++;
for(auto x:a)
if (x.second % 2)
{
cout << "No";
return 0;
}
cout << "Yes";
return 0;
}
C题:Tak and Cards
给定N张卡片,和一个数字A,每张卡片上有对应数字,可以选取1-N张卡片,问有多少种选法使得每次选中的卡片上的数字之和的严格平均值为A
Solution
数据范围直接劝退搜索,那么必然就是DP了
背包问题的变形,在这里问的是方案数
动态规划问题步骤
1.状态表示
dp[i][j][k]:从前i个物品中选j个物品,总和恰好为K的方案数
2.状态转移方程
k<x:dp[i][j][k]=dp[i-1][j][k]
k>=x:dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k-x]
3.边缘情况
dp[i][0][0]=0
4.是否可以降低维度
显然可以
需要将j和k从大到小开始枚举
dp[j][k]=dp[j][k]+dp[j-1][k-x]
Code(未优化)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int x[60];
int dp[60][60][3000];
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int n, a; cin >> n >> a;
for(int i=0;i<=n;i++)
dp[i][0][0] = 1;
for (int i = 1; i <= n; i++)cin >> x[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
for (int k = 1; k <= 2501; k++)
{
if(k<x[i]) dp[i][j][k]= dp[i - 1][j][k];
else dp[i][j][k] = dp[i - 1][j][k]+dp[i-1][j-1][k-x[i]];
}
int sum = 0;
for (int i = 1; i <= n; i++)
sum += dp[n][i][i * a];
cout << sum;
return 0;
}
Code(优化)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int x[60];
int dp[60][3000];
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int n, a; cin >> n >> a;
dp[0][0] = 1;
for (int i = 1; i <= n; i++)cin >> x[i];
for (int i = 1; i <= n; i++)
for (int j = i; j>=1; j--)
for (int k = 2501; k>=x[i]; k--)
{
dp[j][k] +=dp[j - 1][k - x[i]];
}
int sum = 0;
for (int i = 1; i <= n; i++)
sum += dp[i][i * a];
cout << sum;
return 0;
}
D题:Digit Sum
该题一个难点就是正确理解题意
给定两个数字N,S,问是否存在一个进制b,使得N转化为b进制后,每一位的数字之和等于S(注意这里的每一位是该进制下的位,不是单独的一个数字,例如在100进制下,87564的每一位是64,75,8)若存在多个b,取最小的
Solution
若S>N,显然无解
若S==N,显然最小的b是S+1
若S<N,数据范围显然不能考虑从小到大枚举b,后面想到二分,但进制数从小到大变化,转化后的
数位之和没有单调性变化,不能二分
遇事不决,先写公式分析
则题意可以转化为:
1.先枚举b➡[,)
若存在一个b满足,则便为答案
2.若无,则b一定不在[,)中,对于b的范围,我们只能将其缩小至[,] 范围仍然过大,对式子 ,由于 ,可以得出,又因为 我们可以从大到小枚举,时间复杂度降低在
值得注意的一点时,在第二点枚举时,N-S应能整除才能继续,这样可以大大降低常数,同时b可能为1,为1时需要特判,否则进入check函数时会陷入死循环
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, s;
bool check(int x)
{
int sum = 0;
int y = n;
while (y)
{
sum += y % x;
y /= x;
}
return s == sum;
}
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
cin >> n >> s;
if (s > n)cout << -1;
else if (s == n)cout << n + 1;
else
{
int p = sqrt(n);
for (int i = 2; i <= p; i++)
{
if (check(i))
{
cout << i;
return 0;
}
}
for (int i = p; i; i--)
{
if ((n - s) % i == 0)
{
int z = (n - s) / i + 1;
if (z == 1)continue;
if (check(z))
{
cout << z;
return 0;
}
}
}
cout << -1;
}
return 0;
}