Meaning of the questions: n give you the number, a size 8 * I capacity, save a number of how much capacity is required depends on the type of a given number of n k, using the formula log 2 k calculations, if a given capacity can not save all number, choose to reduce the number of types to reduce the storage capacity required for a number of units (to reduce the number of types by replacing the total amount of data change), Q needs to be replaced much minimum number
Solution: The relationship between the input data stored can be determined to obtain a minimum required number of unit volume = KK . 8 the I * / n-;
= And because KK log 2 K can solve for the case in capacity allows, data types can be stored most 2 = K KK
And because the input data may limit the number n <= 4 * 10 ^ 5 ; i.e. 2 kk <=. 5. 4 * 10 ^; kk solve for the minimum equal to 20;
So when kk> = 20 too, they must be fully saved data pruning process ----------
When kk <20 when:
A = KK log 2 K solve for the data type k = 2 ^ kk (Fast Power)
Because the minimum number to be replaced, the replacement must be a priority of the data appeared only once,
Sliding window processing [0, k-1]:
With a window of size k is determined in the window to the minimum number to be replaced
#include<iostream> #include<algorithm> #include<math.h> #include<string> #include<string.h> #include<vector> #include<utility> #include<map> #include<queue> #include<set> #define mx 0x3f3f3f3f #define ll long long using namespace std; map<ll,ll>m; vector<ll>p; ll a[400005]; ll quick_pow(ll base,ll k) { ll ans=1; while(k) { if(k&1) ans=ans*base; base=base*base; k=k/2; } return ans; } int main() { ll n,k,cap;//容量capacity scanf("%lld%lld",&n,&cap); for(int i=0;i<n;i++) scanf("%lld",&a[i]); sort(a,a+n); cap=cap*8;//给定的容量有多大 int kk=cap/n;//由输入的n和cap可以估计每存一个数需要的最少容量是多少 if(kk>=20)//剪枝处理,如果log以2为底kk的对数等于20,解得数字的种类k=2^20,远大于给定输入数据的个数4*10^5 { printf("0\n"); return 0; } k=quick_pow(2,kk);//由估计的容量kk去解最多可以容纳几种不同的数 m[a[0]]++; p.push_back(a[0]); for(int i=1;i<n;i++) { if(a[i]!=a[i+1]) p.push_back(a[i]); m[a[i]]++; } ll cnt=p.size(); if(cnt<=k)//给定得容量能容纳这些数,就不用减少种类 { printf("0\n"); return 0; } else { ll l=0,r=k-1,sum=0; for(int i=l;i<=r;i++) sum=sum+m[p[i]];//统计重复的数有几个 ll one=n-sum;//只出现一次的数的个数 l++;//滑动窗口,这个窗口的大小是k,[0,k-1] r++; while(r<cnt) { sum=sum-m[p[l-1]]+m[p[r]]; ll temp=n-sum; one=min(one,temp); l++; r++; } printf("%lld\n",one); } }