每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!) (B,C,D)

TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!) (B,C,D)

B

B

这道题的大意是给你一个数n,我们可以把这个n,变成x1y1x2y2......xjyj,如果变成这样的形式,我们可以得到一个值
x1y1+x2y2+...+xjyj,我们要把这个数变得尽量的大,但是这里面的x只能是任意个不同的质数(x是由不同的质数相乘得到的)

对于这个n,我们先可以把他变成x1y1x2y2......xjyj,然后对于幂次,如果是1,那么我们可以使用一次,可以(x1+x2+x3)1),对于幂次为2的,我们可以让他使用两次,最后一次是第2次,可以让 (x2+x3)1),对于幂次为3的,可以利用3次,那么对于第三段,这里面的数幂次都是大于等于3

那么我们可以求一个数组 sum[i]i到最大幂次(我们这里用30),的数的乘积,这里面所有的数都只会出现一次,符合条件,而且每一个数都在最大价值的用到了

#include <iostream>
#include <algorithm>
#include <vector>
#include<map>
using namespace std;
#define int long long 
int t,n;
void solve()
{
    cin>>n;
    map<int,int>cnt;
    for (int i=2;i*i<=n;i++)
    {
        if (n%i==0)
        {
            int tot=0;
            while (n%i==0)
            {
                n/=i;
                tot++;
            }
           cnt[i]=tot;
        }
    }
    if (n>1)
    {
        cnt[n]=1;
    }
    vector<int>sum(40,1);
    for (auto[x,tot]:cnt)
    {
        sum[tot]*=x;
    }
    for (int i=30;i>=1;i--)
    {
        sum[i]*=sum[i+1];
    }
    int ans=0;
    for (int i=1;i<=30;i++)
    {
        if (sum[i]>1)
        {
            ans+=sum[i];
        }
    }
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

C

C

这个题大意是给出一个长度为n的数,还有一个s,我们需要构造两个数组xy,

并且满足xi+yi=ai(sxi)(syi)>=0

我们也可以得到一个F,其中F的公式求出如下

F=a1×x2+y2×x3+y3×x4yn2×xn1+yn1×an

然后对于xy,我们要怎么构造呢

反正是乘法,那我们要尽量大的和大的相乘,那么x或者y,要么是那个可以成为的最大的那一个,要么是较小的那一个,那么我们可以记录每一个ai,我们都可以得到一个mxi,mii,然后再求最小

我们还用到了

f[i][0]说明这yimii,那么xi就是mxi

f[i][1]说明这yimxi,那么xi就是mii

然后按照题目中给出的求min

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=2e5+10;
#define int long long 
int f[maxn][2];
int a[maxn],mi[maxn],mx[maxn];
int n,t,s;
void solve()
{
    cin>>n>>s;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        if (a[i]>=2*s)
        {
            mi[i]=s;
            mx[i]=a[i]-s;
        }
        else if (a[i]>=s)
        {
            mx[i]=s;
            mi[i]=a[i]-s;
        }
        else 
        {
            mi[i]=0;
            mx[i]=a[i];
        }
    }
    f[2][0]=a[1]*mi[2];
    f[2][1]=a[1]*mx[2];
    for (int i=3;i<n;i++)
    {
        f[i][0]=min(f[i-1][0]+mx[i-1]*mi[i],f[i-1][1]+mi[i-1]*mi[i]);
        f[i][1]=min(f[i-1][0]+mx[i-1]*mx[i],f[i-1][1]+mi[i-1]*mx[i]);
    }
    int ans=min(f[n-1][0]+mx[n-1]*a[n],f[n-1][1]+mi[n-1]*a[n]);
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

D

D

这个题大意是我们一开始在1的位置,如果我们走到了i位置上,那么下一步我们可以走到i+ai

我们可以把ai变成一个y,(y可以是ai )|y|<=n,如果走到的位置pos,1<=pos<=n,那么他还需要继续走,如果不在这一个范围里,那么说明他可以不再走了,游戏结束

我们可以把ai变成y,可以让我们游戏结束可以确定是走了多少步的改变有多少种(不出现死循环)

我们有两种不同的情况

如果从1就可以直接结束,那么有太多种了,就算是1到不了的点不管怎么改变都可以

所谓正难则反,我们就用所有的改变方法,再减去那些会达到死循环的变化

对于那些可以不会进入死循环的那些点,如果要再是进入那些不会进行死循环的点,那么就相当于这个路程已经出现了循环,那么是不可的

还不可以进入那些本来就是死循环的节点,也是不可

所以不可变成的有siz[u]+n(siz[0]1)个(我们反向建图,对于那些出界的点,我们一律记为0,从0出发,siz[i]是从0到达i有多少个节点,用到siz[0]如果用到要记得减一,不包括本身0)

如果从1出发就是一个死循环,那么对于从1i这一路,没有出现循环之前,每一个点都有以下几种改变可以让这个路径变成可以到达点0

如果此时在i

第一种,直接出界,我们发现,每一个位置,都有n+1个可以直接变成点0,(这里的0不是单纯的0,而是绝对值大于n的数)

第二种,从i走到那些可以到达0的位置,而且那些一定位置一定是没出界的,所以不会重复,有siz[0]1个点

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define int long long 
const int maxn=2e5+10;
int n,t;
vector<int>g[maxn];
int siz[maxn],f[maxn],a[maxn];
vector<bool>vis;
void dfs(int u)
{
    siz[u]=1;
    for (auto v:g[u])
    {
        dfs(v);
        siz[u]+=siz[v];
    }
    return ;
}
void solve()
{
    cin>>n;
    vis=vector<bool>(n+1,false);
    for (int i=0;i<=n;i++)
    {
        g[i].clear();
        siz[i]=0;
    }
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        int nxt=i+a[i];
        if (nxt>n||nxt<=0) nxt=0;
        g[nxt].push_back(i);
        f[i]=nxt;
        if (nxt==0) vis[i]=true;
    }
    dfs(0);
    int ans=0;
    if (siz[1])
    {
        ans=n*(2*n+1);
        int u=1;
        while (u)
        {
            ans-=siz[u];
            ans-=(n-(siz[0]-1));
            u=f[u];
        }
    }
    else 
    {
        vector<int>v(n+1,0);
        int u=1;
        while (u)
        {
            if (v[u]) break;
            v[u]=1;
            ans+=n+1;
            ans+=siz[0]-1;
            u=f[u];
        }
    }
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}
posted @   righting  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示