0
点赞
收藏
分享

微信扫一扫

【补题】2022校赛

半夜放水 2022-03-27 阅读 32
c++算法

A.大整数分解

题目:
在这里插入图片描述
思路:A ^B最快的方法是先求出A的所有质因子, 然后用类似快速幂的方法增加到B次方,因为每个质因子都是独立增加的,假设它的质因子为p1 ^c1, p2 ^c2,p3 ^c3…,如果此时p1、p2、p3这三个因子都算出来了并且都乘上了,而它们的次方c又大于1的话,我们只要同时乘以 p1 * p2 * p3,它们是独立增长的 ,所以只需要知道最大的c就好了。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000100, M=1000000;
int prime[N], st[N], cnt;

void init(){
    for(int i=2; i<=M; i++)
    {
        if(!st[i]) prime[++cnt]=i;
        for(int j=1; prime[j]<=M/i; j++)
        {
            st[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}


int main(){
    int A, B;
    init();
    cin>>A>>B;
    int maxn=0, res1=0;
    for(int i=1; i<=cnt; i++)
    {
        int x=0;
        while(A%prime[i]==0 && A>0)
        {
            x++;
            A/=prime[i];
        }
        if(x)
        {
            res1++;
            maxn=max(x, maxn);
        }
    }
    maxn*=B;
    cout<<res1+(int)ceil(log2(maxn));
    
    return 0;
}

E.规律游走

题目:
在这里插入图片描述
思路:找规律的题, 每4ab走的路线是一样的。具体实现用数字来表示四个方向,j=0为右, j=1为上,j=2为左, j=3为下。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, ll>
#define x first
#define y second

int main(){
    int n, a, b;
    cin>>n>>a>>b;
    int len=4*a*b;
    vector<PII> pace(len+1);
    for(int i=1; i<len+1; i++)
    {
        int j=((i-1)/a-(i-1)/b)%4;//看一下此时是a的几倍,是b的几倍,也就是表示向左转90°转了几次,向右转90°转了几次
        if(j<0) j+=4;//如果是负数,那么就是向右转的次数多于向左转的次数,相当j是正数的逆过程
        pace[i]=pace[i-1];
        if(j==0) pace[i].x++;
        else if(j==1) pace[i].y++;
        else if(j==2) pace[i].x--;
        else pace[i].y--;
    }
    
    cout<<pace[n%len].x+pace[len].x*(n/len)<<" "<<pace[n%len].y+pace[len].y*(n/len);//一共走了多少次这样的循环
    
    return 0;
}

I.巧克力棒

题目:
在这里插入图片描述

思路:题目要求等差数列的数量,2 1 3、3 2 1 这样的等差数列和1 2 3是一样的,因此考虑排序。排完序后,由于等差数列的公差是一样的,一个合法的等差数列加上现在符合这个公差的数就能长度加一,设dp[i][j]为选了第i个数,公差为j的等差数列的数量,由于j的范围很大,开一个map来存,dp[i][ a[i]-a[j] ]=dp[i][ a[i]-a[j] ]+dp[j][ a[i]-a[j] ],最后加上n,也就是长度为1的等差数列。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2100, mod=998244353;
map<int, ll> dp[maxn];
int a[maxn];

int main(){
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];
    sort(a+1, a+n+1);
    for(int i=1; i<=n; i++)//初始化长度为2的等差数列
    {
        for(int j=1; j<i; j++)
        {
            dp[i][a[i]-a[j]]++;
        }
    }
    
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<i; j++)
        {
            dp[i][a[i]-a[j]]=(dp[i][a[i]-a[j]]+dp[j][a[i]-a[j]])%mod;
        }
    }
    
    ll ans=0;
    for(int i=1; i<=n; i++)
    {
        for(auto &j: dp[i])
        {
            ans=(ans+j.second)%mod;
        }
    }
    cout<<(ans+n)%mod;
    
    return 0;
}

I.归零

题目:
在这里插入图片描述
思路:可以进行的操作是对相邻点进行+1或者-1,假设输入数组是一个差分数组,还原出任意一个合法的原数组,这个+1或者-1操作就是对于原数组的一个数进行+1或者-1,答案要求出最小操作次数,也就是使还原出的的这个原数组的每一个数都变成同一个数,让我们求出原数组的每一个数减去这个数的和最小,这里有一个中位数的性质,给定一个数列,所有数与中位数的绝对差之和最小,所以只要求出原数组的每个数减去中位数之和。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=510;
ll a[N], b[N];

int main(){
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) scanf("%lld", &a[i]);
   
    for(int i=2; i<=n; i++) b[i]=b[i-1]+a[i];
    sort(b+1, b+n+1);
    ll ans=0;
    ll x=b[(n+1)/2];
    for(int i=1; i<=n; i++) ans+=abs(b[i]-x);
    cout<<ans;
    
    return 0;
}
举报

相关推荐

0 条评论