CodeForces Round 1061(div.2)A-C
A. Pizza Time
题意:
给定一个n,每次分成三份,A吃第一份,B吃第二份,第三份进入下一轮,如果刚好有2个,则B吃完,求A最多吃多少分
解题思路:
首先确定好最优策略:
A一份,B一份,剩下的进入下一轮
这样的策略能确保A吃的尽可能多
于是我们就可以发现一些规律:
每一轮就是:1 1 n-2
我们就可以去找有几轮即可
即n/2
但是题目还有一个约束条件,当剩余两个时,可以全部被B吃掉
当n为偶数,最后一轮能被B吃掉,A一个都吃不到
当n为奇数,则正常分
于是得到(n-1)/2
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int n;cin>>n;cout<<(n-1)/2<<endl;
}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
B. Strange Machine
题意:
显然是一个模拟,题目不在描述
解题思路:
直接模拟:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int n,q;cin>>n>>q;string s;cin>>s;while (q--){int x;cin>>x;int cnt=0;for(int i=0;i<n;){if(s[i]=='A')x--;else x/=2;cnt++;if(x==0)break;i=(i+1)%n;}cout<<cnt<<endl;}}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
感觉非常简单,然后TLE
我们来看怎么优化:
我们可以发现,时间消耗在--操作,除2运算最多就需要30次,我们需要考虑怎么优化掉--操作。
方式一:我们可以发现当没有B操作时,我们可以直接输出答案,剩下的再模拟。
方式二:压缩连续操作块
详情看:https://codeforces.com/blog/entry/147761
完整代码:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>using namespace std;
typedef long long ll;void solve() {int n, q;cin >> n >> q;string s;cin >> s;vector<int> a(q);for (int i = 0; i < q; i++) {cin >> a[i];}int A = count(s.begin(), s.end(), 'A');int B = count(s.begin(), s.end(), 'B');for (int i = 0; i < q; i++) {if (B == 0) {cout << a[i] << endl;} else {ll ans = 0;int x = a[i];while (x > 0) {for (char j : s) {if (x == 0) break;ans++;if (j == 'A') {x--;} else {x /= 2;}}}cout << ans << endl;}}
}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}
C. Maximum GCD on Whiteboard
解题思路:
我们有两种操作,一种删除,一种拆分,我们先贪心的选择拆分,实在不能拆了,在删除。
先拆分:x=x1+x2+x3,满足1<=x1<=x2<=x3x=x_1+x_2+x_3,满足1<=x_1<=x_2<=x_3x=x1+x2+x3,满足1<=x1<=x2<=x3我们假设满足题目要求的GCD为g,那么x为g的倍数,我们要保留x1和x3x_1和x_3x1和x3,必须确保他们俩都是g的倍数,最合理的拆分就是g+g+2g=xg+g+2g=xg+g+2g=x,这样能确保最小能拆分数,如果小于4*g则不能拆分
即x=4∗gx=4*gx=4∗g
再删除:当x<4*g或者x不是g的倍数,直接删除
问题在于我们如何确定g,答案是枚举
g是整个完美数组的最大公约数(GCD),值不会很大,但是的需要时间复杂度优化
优化一:快速计算需要删除的数
我们选择哈希表加前缀和,把每一个数出现几次存到哈希表中,用前缀和快速计算在对应范围中需要删除的个数
简单说就是:小的非倍数必须删,大的非倍数可以拆。
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int n,k;cin>>n>>k;vector<int>a(n);int maxn= 0;for (int i = 0; i < n; i++) {cin >> a[i];maxn = max(a[i] ,maxn);}vector<int>sum(maxn+1,0),vve(maxn+1,0);for(int i=0;i<n;i++)vve[a[i]]++;for(int i=1;i<=maxn;i++)sum[i]=sum[i-1]+vve[i];int ans=1;for(int d=1;d<=maxn;d++){int r=min(4*d-1,maxn);if(r<1)continue;int sumcnt=sum[r];int cnt=0;for(int i=d;i<=r;i+=d)cnt+=vve[i];if(sumcnt-cnt<=k)ans=d;}cout<<ans<<endl;
}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
