zoukankan      html  css  js  c++  java
  • 题解 P6306 【「Wdsr-1」小铃的书】

    水题解来了


    开始讲

    一步一步来吧,先是(50pt)

    (first--50pt)

    话说这个部分应该都会吧

    其实这个部分就是把所有能想到的做法都拿出来爆搞就是了,比如存储后排序再扫描处理,或者直接用桶存

    而我们现在关心的是后一种做法。为什么?我也不知道,因为这与我们之后的(75pt)以及正解的思路都密切相关。而(50pt)部分的桶做法应该都能想到吧,就是用个(map)暴力存储,再看最后的出现次数是否(mod~k)为零

    (second--75pt)

    可是(map)到了第二个部分(75pt)时,(8mb)会卡得你不要不要的,所以就只能考虑其它的巧了

    依旧考虑桶的思路,而目标是优化空间,那么就考虑将一个数拆成其(k)进制的若干部分,比如(k=3)时,将((5)_ {10})变成((12)_ {3}),而将((12)_ {3})的个位(2)存入专门存个位的桶中,十位(1)存入专门存十位的桶中,这个存其实就是将数加入桶中。而将桶取模(k),若有剩余那么剩下的必然是可以计入答案中的,关于这个我们假设混入的魔导书为(t),其存入的某一位设为第(p)位,则其存入的数值是(ans_p=frac{t\% k^{p+1}}{k^p}),而显然(k^p<t\%k^{p+1}<k^{p+1}),所以(0<ans_p<frac{k^{p+1}}{k^p}=k)(以上除号均是下取整),所以膜(k)后剩下的值一定是答案中的,可以加入

    也就是以下代码:

    fac[0]=1;
    for(register int i=1;fac[i-1]<=lim;up=i++)
    	fac[i]=fac[i-1]*k;
    for(register ll x;n;--n)
    {
    	x=read();
    	for(register int i=up;x;--i)
    		if(x>=fac[i])
    		{
    			ans[i]+=x/fac[i];
    			if(ans[i]>=k)
    				ans[i]-=k;
    			x%=fac[i];
    		}
    }
    for(register int i=up;~i;--i)
    	res+=ans[i]*fac[i];
    

    只给出了一部分,其中(fac_i=k^i),而(res)就是最后答案

    (third--100pt)

    而第二部分的空间(O(log_2a_{max}))是合格了,但显然时间(O(nlog_ka_{max}))被卡掉了,所以考虑进一步优化

    继续考虑桶与拆分的思路,可以想到把(second)中的空间稍微开大一点以达到节约时间的目的

    将一个数分成若干个部分,但这次不是统计那个部分的代数和了,而是统计某个数的该部分的出现次数,这样就可以成功解决问题了

    比如将一个数(a)分为(a_{1-8})(8)个部分,其中(2^{8* (i-1)}<=a_i<2^{8* i}),那么再建立(8)个数组(ans_{i,j}),其中(ans_{i,a_i})自加,那么这些数组就跟一个个小桶一样了,时间也节约了很多,只是(O(n))套了一个(8)的常数,而能顺利解决问题

    至于开(8)个数组只是怕(MLE),其实应该可以开更小的,但(8)个已经够了,不会(T)

    短小精悍的代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    inline ll read()
    {
    	ll x=0,ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar());
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    	return x;
    }
    
    const int digit=1<<8,p=8;
    
    int a[p][digit];
    ll ans,n,k;
    
    int main()
    {
    	n=read(),k=read();
    	for(register ll x;n;--n)
    	{
    		x=read();
    		for(register int i=0;i<p;++i)
    			++a[i][(x>>(i*p))&(digit-1)];
    	}
    	for(register ll i=1;i<digit;++i)
    		for(register int j=0;j<p;++j)
    			if(a[j][i]%k)
    				ans+=(i<<(j*p));
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    WebAPI下的如何实现参数绑定
    MYSQL主从不同步延迟原理
    mysql的limit经典用法及优化
    ASP.NET MVC中的模型绑定
    使用EF实现数据库的增删改查
    NoSQL数据库技术特性解析之文档数据库
    MySQL 缓存 Query Cache
    Loadrunner test web service which need username and password
    vb写文件时报'Invalid procedure call or argument'
    Shell 笔记
  • 原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/12673564.html
Copyright © 2011-2022 走看看