CodeForces - 1490

CodeForces - 1490

A - Dense Array

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
int t,n,a[maxn];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        int ans=0;
        scanf("%d",&n);
        rep(i,1,n)scanf("%d",&a[i]);
        rep(i,1,n-1)
        {
            int maxx=max(a[i],a[i+1]);
            int minn=min(a[i],a[i+1]);
            while(maxx>2*minn)
            {
                minn*=2;
                ans++;
            }
        }
        W(ans);
    }
    return 0;
}



B - Balanced Remainders

由多的给少的,最后达到平衡

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
int t,n,a[maxn],c0,c1,c2,ans;
void solve()
{
    if (c0>n/3)
    {
        c1+=c0-n/3;
        ans+=c0-n/3;
        c0=n/3;
    }
    if (c1>n/3)
    {
        c2+=c1-n/3;
        ans+=c1-n/3;
        c1=n/3;
    }
    if (c2>n/3)
    {
        c0+=c2-n/3;
        ans+=c2-n/3;
        c2=n/3;
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        c0=0,c1=0,c2=0,ans=0;
        scanf("%d",&n);
        rep(i,1,n)
        {
            scanf("%d",&a[i]);
            if (a[i]%3==0)c0++;
            if (a[i]%3==1)c1++;
            if (a[i]%3==2)c2++;
        }
        while(!(c0==c1&&c1==c2))
        {
            solve();
        }
        W(ans);
    }
    return 0;
}



C - Sum of Cubes

O(1e4)预处理出所有的三次方数

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
ll t,x;
map<ll,int> M;
bool find_(ll x)
{
    for (ll i=1;i<=10000;i++)
    {
        if (x<=i*i*i)break;
        if (M[x-i*i*i])return true;
    }
    return false;
}
int main()
{
    scanf("%lld",&t);
    for (ll i=1;i<=10000;i++)M[i*i*i]=1;
    while(t--)
    {
        scanf("%lld",&x);
        if (find_(x))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}



D - Permutation Transformation

递归:每遇到一个最大值,就分两段,并深度加1

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
int t,n,a[maxn],ans[maxn];
void solve(int num,int l,int r)
{
    int maxx=0,pos=-1;
    if (l>r)return;
    rep(i,l,r)
    {
        if (a[i]>maxx)
        {
            maxx=a[i];
            pos=i;
        }
    }
    ans[pos]=num;
    solve(num+1,l,pos-1);
    solve(num+1,pos+1,r);
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        rep(i,1,n)scanf("%d",&a[i]);
        solve(0,1,n);
        rep(i,1,n)printf("%d ",ans[i]);puts("");
    }
    return 0;
}



E - Accidental Victory

反向遍历,对于位置为i的人
如果前缀和sum[i]>=a[i+1],就有机会赢
如果sum[i]<a[i+1],不论如何都赢不了a[j](j>i),这种情况直接break因为再前面的人更不可能赢

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
struct node
{
    ll x;
    int id;
}p[maxn];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int n,t;
ll sum[maxn];
vector<int>ans;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        ans.clear();
        scanf("%d",&n);
        rep(i,1,n)
        {
            scanf("%lld",&p[i].x);
            p[i].id=i;
        }
        sort(p+1,p+1+n,cmp);
        rep(i,1,n)sum[i]=sum[i-1]+p[i].x;
        ans.pb(p[n].id);
        for (int i=n-1;i>=1;i--)
        {
            if (sum[i]>=p[i+1].x)ans.pb(p[i].id);
            else break;
        }
        sort(ans.begin(),ans.end());
        W(ans.size());
        repp(i,0,ans.size())printf("%d ",ans[i]);puts("");
    }
    return 0;
}



F - Equalize the Array

预处理出每个数量的人共有多少组
比如数组 a a a=[1,1,1,2,2,3,3],那么 n u m { 1 , 2 , 3 } = { 0 , 2 , 1 } num\{1,2,3\}=\{0,2,1\} num{1,2,3}={0,2,1}

C = i , a n s = 0 C=i,ans=0 C=i,ans=0
对于 ∀ j < i \forall j<i j<i必须全部消除, a n s + = ∑ j = 1 i − 1 ( n u m [ j ] ∗ j ) ans+=\sum_{j=1}^{i-1}(num[j]*j) ans+=j=1i1(num[j]j)
对于 ∀ j < i \forall j<i j<i必须全部消除到 i i i个才可以,可以用一个变量 p r e pre pre和后缀和去完成
两部分加起来,不断取min就是答案

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
int t,n,a[maxn],m,b[maxn],c[maxn],num[maxn],sum[maxn],ans,num1[maxn],bac[maxn];
int query(int x)
{
    return lower_bound(b+1,b+1+m,x)-b;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        m=0;ans=INF;
        scanf("%d",&n);
        rep(i,1,n)scanf("%d",&a[i]);
        rep(i,0,n+1)num1[i]=num[i]=sum[i]=bac[i]=0;
        sort(a+1,a+1+n);
        rep(i,1,n)if (i==1||a[i]!=a[i-1])b[++m]=a[i];
        rep(i,1,n)
        {
            c[i]=query(a[i]);
            num1[c[i]]++;
        }
        rep(i,1,n)num[num1[i]]++;
        rep(i,1,n)sum[i]=sum[i-1]+i*num[i];
        for (int i=n;i>=1;i--)bac[i]=bac[i+1]+num[i];
        int pre=0;
        for (int i=n;i>=1;i--)
        {
            pre+=bac[i+1];
            ans=min(ans,pre+sum[i-1]);
        }
        W(ans);
    }
    return 0;
}



G - Old Floppy Drive

分三种情况:
1.如果sum[n]<=0并且最大的前缀和都比x小,则输出-1
2.如果最大的前缀和大于等于x,那么一定是一轮就可以输出的
3.需要进行多轮,那么先让x减去最大的前缀和,然后整除算出需要多少轮

接下来二分找出具体位置
假设前缀和数组为1,0,3,5,4
显然
如果取不到1,更不可能取到0,意味着可以修改为递增数组1,1,3,5,5

const int maxn=2e6+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
ll t,n,m,a[maxn],x[maxn],sum[maxn],maxx[maxn];
int main()
{
    scanf("%lld",&t);
    while(t--)
    {
        maxx[0]=-INFF;
        scanf("%lld%lld",&n,&m);
        rep(i,1,n)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i],maxx[i]=max(maxx[i-1],sum[i]);
        rep(i,1,m)
        {
            scanf("%lld",&x[i]);
            if (sum[n]<=0&&maxx[n]<x[i])printf("%d ",-1);
            else if (maxx[n]>=x[i])
            {
                ll ans=lower_bound(maxx+1,maxx+1+n,x[i])-maxx-1;
                printf("%lld ",ans);
            }
            else
            {
                ll k=(x[i]-maxx[n]+sum[n]-1)/sum[n];
                ll ans=n*k;
                ans+=lower_bound(maxx+1,maxx+1+n,x[i]-sum[n]*k)-maxx-1;
                printf("%lld ",ans);
            }
        }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值