A. Only Pluses
暴力题
不难发现数据范围很小,直接暴力计算最大值即可
或者每次给最小的 ++ ,用最小堆来维护
void Rainbow_()
{
int a,b,c;
cin >> a >> b >> c;
priority_queue<int, vector<int>, greater<int> > q;
q.push(a);q.push(b);q.push(c);
int cnt = 5;
while( cnt ) {
int w = q.top();
w ++ ;
q.pop();
q.push(w);
cnt -- ;
}
a = q.top();q.pop();
b = q.top();q.pop();
c = q.top();q.pop();
cout << a * b * c << '\n';
return ;
}
or
void Rainbow_()
{
int a,b,c;
cin >> a >> b >> c;
int ans = -1;
for(int i = 0; i <= 5; i ++ ) {
for(int j = 0; i + j <= 5; j ++ ) {
for(int k = 0 ; i + j + k <= 5; k ++ ) {
ans = max( (a +i) * (b + j) * ( c + k ) , ans );
}
}
}
cout << ans << '\n';
return ;
}
B. Angry Monk
英语阅读能力测试题
贪心的把所有移动到最大的
void Rainbow_()
{
int n,k;
cin >> n >> k;
vector<int> a(k);
for(int i = 0 ; i < k ; i ++ ) {
cin >> a[i];
}
sort(a.begin(),a.end());
int ans = 0;
for(int i = 0 ; i < k - 1; i ++ ) {
ans += a[i] * 2 - 1;
}
cout << ans << '\n';
return ;
}
C. Gorilla and Permutation\
一个简单构造题
答案分为三段 , 我们需要查看每段的贡献.
g数组在小于等于 m 的时候有贡献 ,f数组在大于等于k的时候有贡献,又因为 m < k 所以我们没有办法使得两个数组同时出现贡献,所以我们贪心的选择更大的贡献,也就是
区间1 : 先从大到小输出最大的k个数字
区间2: m ~ k这个区间里面我们可以任意输出
区间3: 1~m的区间我们从小到大输出前m个字
如果直接按照这三个区间写,会出现一些边界的问题,我们可以合并前两个循环来实现
自己探究为什么写三个循环会出现边界问题捏
void Rainbow_()
{
int n,m,k;
cin >> n >> m >> k;
for(int i = n; i > m; i -- ) {
cout << i << ' ';
}
for(int i = 1; i <= m; i ++ ) {
cout << i << ' ';
}
cout << '\n';
return ;
}
D. Test of Love
典型的 DP
我们用 dp[i]来表示 游到第 i 个位置所需要的最小游泳距离
不难得到 转移方程
把这三个式子写出来就AC了
void Rainbow_()
{
int n,m,k;
cin >> n >> m >> k;
string s;
cin >> s;
s = 'L' + s + 'L';
vector<int> dp(n + 2,INF);
dp[0] = 0;
for(int i = 1; i <= n + 1 ; i ++ ) {
if (s[i] == 'C' ) {
continue ;
}
if(s[i - 1] == 'W' ) {
dp[i] = min(dp[i],dp[i - 1] + 1);
}
for(int j = 1; j <= m; j ++ ) {
if( i < j ) {
break ;
}
if (s[i - j] == 'L' ) {
dp[i] = min(dp[i] , dp[i - j]);
}
}
}
if( dp[n + 1] <= k ) {
cout << "YES\n";
} else {
cout << "NO\n";
}
return ;
}
E. Novice's Mistake
如果枚举再范围内的所有情况那么必定超时 , 所以我们观察题目
首先题目要求 S 非空, 所以 n *a - b < n * a <= 1e7 必定为真 , 所以最后的结果最多7位
所以 b 的范围就确定为
直接枚举 a 和 b的值在模拟即可
void Rainbow_()
{
int n;
cin >> n;
string s = to_string(n);
int t = 1;int len = s.size();
for(int i = 0 ; i < len ; i ++ ) {
t *= 10;
}
vector<int> tmp;
for(int i = 0 ; i < len ; i ++ ) {
tmp.pb(s[i] - '0');
}
vector< pair<int,int> > ans;
for(int a = 1; a <= 1e4; a ++ ) {
for(int b = max( 1ll , len * a - 7) ; b <= len * a - 1; b ++ ) {
int res1 = n * a - b;
int res2 = 0;
int k = len * a - b;
while( k > 0 ) {
if( k >= len ) {
k -= len ;
res2 = res2 * t + n;
} else {
for(int o = 0 ; o < k ; o ++ ) {
res2 = res2 * 10ll + tmp[o];
}
k = 0;
}
}
if(res1 == res2 ) {
ans.pb({a,b});
}
}
}
cout << (int) (ans.size() ) << '\n';
for(auto it : ans ) {
cout << it.x << ' ' << it.y << '\n';
}
return ;
}
F. Valuable Cards
最佳策略就是从头开始尽可能的取,直到取第 ai 个的时候不符合条件了 , 便回退一格 , 另开始取新的一段 , 用一个 f 数组 来维护当前是否可以凑出 i
void solve()
{
cin>>n>>x;
map<int,int>dp;
for(int i=1;i<=n;i++)cin>>a[i];
vector<int>f;
for(int i=1;i<=x/i;i++)
if(x%i==0)
{
f.push_back(i);
if(i!=x/i)f.push_back(x/i);
}
dp[1]=1;
sort(f.begin(),f.end());
reverse(f.begin(),f.end());
int ans=0;
for(int i=1;i<=n;i++)
{
for(int y:f)if(dp[y])dp[y*a[i]]=1;
bool ok=false;
if(dp[x])
{
//cout<<i<<endl;
ans++;
i--;
dp.clear();
dp[1]=1;
}
}
cout<<ans+1<<endl;
}
另一个简单的方法,我们可以用set来维护 (前提数学条件 : 一个数 x 能被最多logx 个数除完。)
所以我们可以直接枚举,用 set 存储当前要选的一段区间中所有能区间中一些数相乘得到 x 的数。如果后面遇到的 set 中的某个数,则需要从这个开始划分一个新的区间。
void Rainbow_()
{
int n,x;
cin >> n >> x;
set<int> s;
int cnt = 0;
for(int i = 1; i <= n; i ++ ) {
int a;cin >> a;
if( s.find(a) != s.end() ) {
cnt ++;
s.clear();
}
auto tmp = s;
for(auto c : tmp) {
if( c % a == 0 ) {
s.insert(c / a);
}
}
if( x % a == 0 ) {
s.insert( x / a );
}
}
cout << cnt + 1 << '\n';
return ;
}