AcWing 第 57 场周赛总结
T1 比大小
简单的一道签到题。
T2 数字操作
考虑分解质因数,最后的答案就是所有质因数乘起来,操作次数就是一次乘法再加上开方的次数,也有可能不乘直接开方。
乘法的作用是把每个质因数的指数变成 \(2^n\) 的形式,这样开方就可以开尽。答案就是 \(n + 1\) 或者 \(n\)。但要记得特判 \(1\) 的情况,考试的时候被卡了 \(4\) 次。
下面是 AC 的代码
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
struct node{
int base, expo;
};
int n, m, res = 1, step;
int prime[MAXN];
bool vis[MAXN];
vector<node> fac;
void find_prime(){
vis[1] = true;
for(int i = 2; i <= n; i++){
if(!vis[i]){
prime[++m] = i;
for(int j = i * 2; j <= n; j += i){
vis[j] = true;
}
}
}
}
void divide(int x){
for(int i = 1; i <= m; i++){
int cnt = 0;
while(x % prime[i] == 0){
x /= prime[i];
cnt++;
}
if(cnt != 0) fac.push_back((node){prime[i], cnt});
}
}
bool check(int x){
for(int i = 0; i < fac.size(); i++){
if(fac[i].expo != x) return false;
}
return true;
}
int main(){
scanf("%d",&n);
if(n == 1){
printf("1 0\n");
exit(0);
}
find_prime();
divide(n);
for(int i = 0; i < fac.size(); i++){
res *= fac[i].base;
}
int maxn = 0;
for(int i = 0; i < fac.size(); i++){
maxn = max(maxn, fac[i].expo);
// printf("base = %d expo = %d\n",fac[i].base,fac[i].expo);
}
step = log2(maxn);
if((1 << step) != maxn){
step += 2;
}else{
if(!check(maxn)) step++;
}
printf("%d %d\n",res,step);
return 0;
}
T3 最长连续子序列
开始想到用二分做,但是后面自己证明了没有单调性,所以是一个错误的算法,但是还是拿到了 \(80\%\) 的点。(但是居然被 lyw 两遍二分骗过了,可恶)
二分错误代码:
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
typedef long long ll;
ll n, maxn;
ll a[MAXN], sum[MAXN];
bool check(ll len){
for(ll i = 1; i + len - 1 <= n; i++){
ll tmp = sum[i + len - 1] - sum[i - 1];
if(tmp > 100 * len) return true;
}
return false;
}
void solve(){
ll l = 1, r = n, res = 0, mid;
while(l <= r){
mid = (l + r) >> 1;
if(check(mid)){
l = mid + 1;
res = mid;
}else{
r = mid - 1;
}
}
printf("%lld\n",res);
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(ll i = 1; i <= n; i++) scanf("%lld",&a[i]), maxn = max(maxn, a[i]);
if(maxn <= 100){
printf("0\n");
exit(0);
}
for(ll i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
solve();
return 0;
}
然后想到把每一个数字都减去 \(100\),然后求最长的区间和大于零的连续子序列,但是求长度的时候打爆了,只有 \(50\%\) 的点拿到了
错误但接近正解的代码:
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
typedef long long ll;
ll n, sum, ans, l = 1, r;
ll a[MAXN];
int main(){
// freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(ll i = 1; i <= n; i++){
scanf("%lld",&a[i]);
a[i] -= 100;
}
for(int i = 1, now_l = 1; i <= n; i++){
sum += a[i];
if(sum < 0){
sum=0;
now_l = i + 1;
}else if(sum > 0){
r = i;
l = now_l;
}
}
printf("%d\n", r - l + 1);
return 0;
}
最后没有打出正解,但是考完以后按照题解的思路,用单调栈打出来了
正解代码:
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
typedef long long ll;
ll n, ans, top;
ll a[MAXN], sum[MAXN], st[MAXN];
int main(){
// freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(ll i = 1; i <= n; i++){
scanf("%lld",&a[i]);
a[i] -= 100;
}
for(ll i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
st[++top] = 0;
for(ll i = 1; i <= n; i++){
if(sum[st[top]] > sum[i]) st[++top] = i;
else if(sum[st[top]] < sum[i]){
int l = 1, r = top, mid, res;
while(l <= r){
mid = (l + r) >> 1;
if(sum[st[mid]] < sum[i]){
r = mid - 1;
res = mid;
}else{
l = mid + 1;
}
}
ans = max(ans, i - st[res]);
}
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号