• AtCoder Beginner Contest 143 F


    题意

    给出一个长度为NN的序列,求对于所有k[1,N]kin[1,N],每次从序列中选出kk个互不相同的数,最多能取多少次。
    N3e5Nle3e5

    题解

    我们首先把数组转化为相同的数的出现次数的序列,如序列(1,3,4,4)(1,3,4,4)就转化为(1,1,2)(1,1,2)。把这个得到的序列计作aa

    然后二分答案,假设当前二分到xx,能取xx次的条件是:
    (aixai)+xai>x1kxlarge(sum_{a_ile x}a_i)+xcdotsum_{a_i>x}1ge kcdot x因为同一个数最多取到xx次,而取到的总数为kxkcdot x

    发现当kk增大时答案减小,所以可以把二分去掉,写一个指针动就行了。这样的时间复杂度是O(nlogn)O(nlog n)的,因为要upper_boundupper\_bound

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    inline void rd(int &x) {
    	char ch; for(;!isdigit(ch=getchar()););
    	for(x=ch-'0';isdigit(ch=getchar());)x=x*10+ch-'0';
    }
    typedef long long LL;
    const int MAXN = 300005;
    int N, n, a[MAXN], cnt[MAXN];
    LL sum[MAXN];
    int ans[MAXN];
    
    inline bool chk(int k, int x) {
    	int pos = upper_bound(a + 1, a + n + 1, x) - a;
    	return sum[pos-1] + 1ll*(n-pos+1)*x >= 1ll*k*x;
    }
    
    int main() {
    	rd(N);
    	for(int i = 1, x; i <= N; ++i) rd(x), ++cnt[x];
    	for(int i = 1; i <= 300000; ++i) if(cnt[i]) a[++n] = cnt[i];
    	sort(a + 1, a + n + 1);
    	for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];
    	int now = 0;
    	for(int k = n; k >= 1; --k) {
    		while(now < N && chk(k, now+1)) ++now;
    		ans[k] = now;
    	}
    	for(int i = 1; i <= N; ++i) printf("%d
    ", ans[i]);
    }
    

    然而看了别人的博客后发现,可以O(n)O(n)
    上代码:

    sum[x]sum[x]存的就是上面的不等式的左边部分。

    #include <bits/stdc++.h>
    using namespace std;
    inline void rd(int &x) {
    	char ch; for(;!isdigit(ch=getchar()););
    	for(x=ch-'0';isdigit(ch=getchar());)x=x*10+ch-'0';
    }
    typedef long long LL;
    const int MAXN = 300005;
    int n, cnt[MAXN];
    LL sum[MAXN];
    int ans[MAXN];
    
    inline bool chk(int k, int x) { return sum[x] >= 1ll*k*x; }
    
    int main() {
    	rd(n);
    	for(int i = 1, x; i <= n; ++i) rd(x), ++cnt[x], ++sum[cnt[x]];
    	for(int i = 1; i <= n; ++i) sum[i] += sum[i-1];
    	int now = 0;
    	for(int k = n; k >= 1; --k) {
    		while(now < n && chk(k, now+1)) ++now;
    		ans[k] = now;
    	}
    	for(int i = 1; i <= n; ++i) printf("%d
    ", ans[i]);
    }
    

    正确性读者自证不难

  • 相关阅读:
    [读书笔记]SQLSERVER企业级平台管理实践读书笔记--从等待事件判断性能瓶颈
    Docker machine学习
    不同数据库连接字符串的网站
    Windows 可以操纵linux内文件,与本地一致的工具
    OpenSSH 安全漏洞(CVE-2021-28041)修复(升级OpenSSH至最新版本(8.6p1))
    PostgreSQL
    firewalld添加/删除服务service,端口port
    PostgreSQL 序列操作
    PostgreSQL/pgsql 为表添加列/ 判断列存不存在再添加列
    Windows10中Power Shell(x64)出现“无法加载 PSReadline 模块。控制台在未使用 PSReadline 的情况下运行。”的解决办法
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039197.html
Copyright © 2020-2023  润新知