首页 > 其他分享 >我也不知道我是不是糖丸

我也不知道我是不是糖丸

时间:2024-10-15 13:23:53浏览次数:4  
标签:mini int top 是不是 chifan maxn 糖丸 知道 first

模拟赛碰到一个很纸张的题目,但是自己没有做出来,于是记一下。

description

pAtW74J.png

\(1 \le n, a_i \le 3 \times 10^5\)。

solution

首先场上我写了一个很典的暴力做法。

考虑到预处理出所有阶乘的质因子幂次,然后相当于我从大往小枚举,能除多少就除多少,这样肯定能够满足字典序最大,然后发现除法对应到质因子幂次上就变成了减法,于是就变成了一个求最大的 \(c\) 使得 \(a - c \times b \ge 0\),直接除一下就做完了,放带代码:

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 3e5 + 5;

int n;
int a[N], prime[N];
vector < int > p;
vector < pair < int, int > > ans;
vector < int > chifan[N], szy;

void init () {
    for ( int i = 2; i <= 7000; i ++ ) {
        if ( !prime[i] ) {
            for ( int j = i + i; j <= 7000; j += i ) {
                prime[j] = 1;
            }
        }
    }
}

signed main () {
    freopen ( "secure.in", "r", stdin );
    freopen ( "secure.out", "w", stdout );
    ios :: sync_with_stdio ( false );
    cin.tie ( 0 ), cout.tie ( 0 );
    cin >> n;
    init ();
    for ( int i = 2; i <= 7000; i ++ ) {
        if ( !prime[i] ) {
            p.push_back ( i );
        }
    }
    for ( int i = 2; i <= 7000; i ++ ) {
        int tmp = i;
        for ( int j = 0; j < p.size (); j ++ ) {
            int cnt = 0;
            while ( tmp % p[j] == 0 ) {
                cnt ++;
                tmp /= p[j];
            }
            chifan[i].push_back ( cnt );
        }
    }
    for ( int i = 3; i <= 7000; i ++ ) {
        for ( int j = 0; j < p.size (); j ++ ) {
            chifan[i][j] += chifan[i - 1][j];
        }
    }
    for ( int i = 0; i < p.size (); i ++ ) {
        szy.push_back ( 0 );
    }
    for ( int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        if ( a[i] != 1 ) {
            for ( int j = 0; j < p.size (); j ++ ) {
                szy[j] += chifan[a[i]][j];
            }
        }
    }
    for ( int i = 7000; i >= 2; i -- ) {
        int mini = 1e18;
        for ( int j = 0; j < p.size (); j ++ ) {
            if ( chifan[i][j] ) {
                mini = min ( mini, szy[j] / chifan[i][j] );
            }
        }
        if ( mini ) {
            ans.push_back ( { i, mini } );
            for ( int j = 0; j < p.size (); j ++ ) {
                szy[j] -= mini * chifan[i][j];
            }
        }
    }
    cout << ans.size () << '\n';
    for ( pair < int, int > x : ans ) {
        cout << x.first << " " << x.second << '\n';
    }
    return 0;
}

但是很明显,这样做是 \(O(nV)\) 的,非常不好,我们考虑优化。

发现从大往小枚举阶乘的过程中,相当于我乘上一个 \(\frac{1}{i}\),对应的质因子幂次减去一个数,发现更改项最多是质因子个数级别,也就是 \(O(\log V)\) 级别,于是我们可以暴力在线段树上更改,然后我们要求的就是 \(a_i - c \times b_i\),这个东西我们转化成 \(\frac{a}{b}\),然后求一个最小值,和区间和即可。其实我也可以维护一个 \(a_i\) 真实值为 \(a_i - c \times b_i\) 的标记,考虑到每次单点修改直接把 tag 更新赋值为 \(0\) 就好

代码(因为我懒所以复制的 ChiFAN 的代码):

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 3e5+114;
int pri[maxn];
void init(){
    for(int i=2;i<maxn;i++){
        if(pri[i]==0){
            for(int j=2;i*j<maxn;j++) pri[i*j]=i;
        }
    }
}
const int inf = 1e18+114;
vector< pair<int,int> > d[maxn];
int cnt[maxn],now[maxn];
int top = 3e5+100;
multiset<int> S;
int n;
int a[maxn];
int b[maxn];
vector< pair<int,int> > ans;
int tr[maxn<<2];//min(cnt/now)
int tag[maxn<<2];
void pushdown(int cur){
    if(tag[cur]!=0){
        if(tr[cur<<1]!=inf) tr[cur<<1]-=tag[cur];
        if(tr[cur<<1|1]!=inf) tr[cur<<1|1]-=tag[cur];
        tag[cur<<1]+=tag[cur];
        tag[cur<<1|1]+=tag[cur];
        tag[cur]=0;
    }
}
void pushup(int cur){
    tr[cur]=min(tr[cur<<1],tr[cur<<1|1]);
}
void change(int cur,int lt,int rt,int pos){
    if(lt==rt){
        cnt[lt]-=tag[cur]*now[lt];
        tag[cur]=0;
        tr[cur]=(now[lt]==0?inf:(cnt[lt]/now[lt]));
        return ;
    }
    int mid=(lt+rt)>>1;
    pushdown(cur);
    if(pos<=mid) change(cur<<1,lt,mid,pos);
    else change(cur<<1|1,mid+1,rt,pos);
    pushup(cur);
}
void del(){
    for(pair<int,int> x:d[top]) change(1,1,maxn-1,x.first);
    for(pair<int,int> x:d[top]) now[x.first]-=x.second;
    for(pair<int,int> x:d[top]) change(1,1,maxn-1,x.first);
    top--;
}
signed main(){
    freopen("secure.in","r",stdin);
    freopen("secure.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    init();
    for(int i=2;i<maxn;i++){
        int x=i;
        while(pri[x]!=0){
            int y=pri[x];
            int s=0;
            while(x%y==0) x/=y,s++;
            d[i].push_back(make_pair(y,s));
        }
        if(x!=1) d[i].push_back(make_pair(x,1));
    }
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[1]++;
        b[a[i]+1]--;
    }
    for(int i=1;i<maxn;i++){
        b[i]+=b[i-1];
        for(pair<int,int> x:d[i]) cnt[x.first]+=b[i]*x.second;
    }
    for(int i=2;i<=top;i++){
        for(pair<int,int> x:d[i]) now[x.first]+=x.second;
    }
    for(int i=1;i<maxn;i++) change(1,1,maxn-1,i);
    while(top>1){
        while(top>1&&tr[1]<1) del();
        if(top<=1) break; 
        ans.push_back(make_pair(top,tr[1]));
        int t=tr[1];
        tr[1]-=t;
        tag[1]+=t;
        del();
    }
    cout<<ans.size()<<'\n';
    for(pair<int,int> x:ans) cout<<x.first<<' '<<x.second<<'\n';
    return 0;
}
/*
4
114 514 1919 810
*/
/*
5
6 7 8 9 10
*/

标签:mini,int,top,是不是,chifan,maxn,糖丸,知道,first
From: https://www.cnblogs.com/alexande/p/18467226

相关文章

  • 地信人考公之前,需要知道的事?
    在当前的就业环境下,越来越多的同学看中职业的稳定性,纷纷涌入考公考编的赛道。本文搜集整理了一些关于地信、测绘、遥感等专业,考公考编需要知道的事情,希望对你有所帮助!地信人考公前要搞清楚的专业代码分类考公考编的岗位一般不会要求一级学科(070500),大多数是要求一级学......
  • 问:JVM的垃圾收集算法你知道哪些,有什么区别?
    GC(垃圾回收器)的概念GC,即垃圾回收(GarbageCollection),是计算机程序中一种自动管理内存的机制。其目的是自动回收不再被使用的对象所占用的内存空间,从而避免内存泄漏和内存溢出,确保程序能够稳定、高效地运行。GC算法的主要特点GC算法有多种,每种算法都有其独特的工作原理和适......
  • 成为一名厉害的黑客,必须知道的12个步骤,黑客入门
        黑客攻防是一个极具魅力的技术领域,但成为一名黑客毫无疑问也并不容易。你必须拥有对新技术的好奇心和积极的学习态度,具备很深的计算机系统、编程语言和操作系统知识,并乐意不断地去学习和进步。如果你想成为一名优秀的黑客,下面是10种最重要的基础条件,请认真阅读:1.了......
  • 2024年最新AI写作工具指南,你知道哪款最好用吗?
    每天对着电脑码字,是不是有时候感觉灵感被掏空了,只能盯着闪烁的光标发呆?也许你甚至怀疑自己是不是该转行了,别急,这可能只是因为——你的工具还不够给力!面对琳琅满目的AI写作工具,你是否也曾迷茫过?真的能够帮助你提高效率吗?一起来看看吧!这篇文章将为你推荐2024年最强大的几款......
  • 2024年还不知道如何清理c盘?最齐全的C盘清理指南!(非常详细)零基础入门到精通,收藏这一篇就
    这段时间以来,我收到最多的问题还是问如何解决C盘爆满,那么今天就来给大家详细讲述一下该怎么给C盘“瘦身”。我之前在文章《带你全面了解你的C盘!并且给它“瘦身”!》中讲到过C盘各个文件夹的作用,也提到过一些清理C盘的方法,但是它并不全面,大家都知道C盘中存放着很多的系统文件......
  • 域名解析错误是不是被限制了?
    在我们畅游互联网的过程中,有时会遭遇域名解析错误的情况,这无疑会给我们的上网体验带来困扰。而很多人在遇到域名解析错误时,不禁会疑惑:这是不是意味着被限制了呢?首先,域名解析错误并不一定意味着被限制。域名解析是将域名转换为对应的IP地址的过程,就如同在电话簿中查找电话号码一......
  • 这波高颜值的官网界面,不知道让多少用户沦陷了
    高颜值的官网界面确实有着强大的吸引力,让众多用户为之“沦陷”。一个拥有高颜值官网界面的网站,首先在视觉上就给用户带来了极大的冲击。精心设计的布局、和谐的色彩搭配以及精美的图片和动画效果,使得整个网站仿佛一件艺术品,让人赏心悦目。这种视觉上的享受能够瞬间抓住用户......
  • 第二十一篇:你知道直播,小区视频点播等是怎么实现的吗?(组播协议)
    你知道直播,小区视频点播等是怎么实现的吗?其实现就是运用了组播!信息从信息源发送给组播成员,肯定不能全网无选择的传播,那不是组播,那就是广播了,路由器不支持广播,却支持组播!为了让信息更快的到达组播成员,需要建立组播路由和组播成员管理。1、组播协议由两部分协议组成1)组成员......
  • 我整理了 50 多个简历致命问题,知道为什么投简历没回复了!
    大家好,我是程序员鱼皮。做知识分享这些年来,我看过太多简历、也帮忙修改过很多的简历,发现很多同学是完全不会写简历的、会犯很多常见的问题,不能把自己的优势充分展示出来,导致措施了很多面试机会,实在是很可惜。为此,我写了一份《程序员写简历指南(保姆级)》专栏,多达几万字,帮大家了解:......
  • 数据科学初学者都应该知道的 15 个基本统计概念
    一、介绍数据科学的核心是统计学,它已经存在了几个世纪,但在当今的数字时代仍然至关重要。为什么?因为基本的统计概念是数据分析的支柱,使我们能够理解每天生成的大量数据。这就像与数据对话,统计学可以帮助我们提出正确的问题并理解数据试图讲述的故事。        从预......