洛谷P6104 相同的数字
首先把 $a$ 排序。不难发现只有两种可能方案:把所有数改成 $a_n$,改成不小于 $a_n$ 的第一个质数。
对于每个数,把它改成大于它的第一个质数,再改成第二个……这些过程可以拆开来放在一起,对于短于 $\frac{c_2}{c_1}$ 的区间用第一种方案,更长的用第二种。
一些细节:如果 $a_n$ 不是质数,那么改成 $a_n$ 只能用第一种方案;过程总数可能很多,但区间长度不会超过154,所以用前缀和记一下就可以做到 $O(nloga_i+q)$。
#include<cstdio> #include<algorithm> #define For(i,A,B) for(i=(A);i<=(B);++i) using namespace std; typedef long long ll; const int N=100050; const int BUF=1<<23; char rB[BUF],*rS,*rT,wB[BUF+50]; int wp=-1; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;} inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } short buf[25]; inline void wt(ll x){ if(wp>BUF)flush(); short l=-1; while(x>9){ buf[++l]=x%10; x/=10; } wB[++wp]=x|48; while(l>=0)wB[++wp]=buf[l--]|48; wB[++wp]='\n'; } bool f[10000020]; int p[670000],cnt,a[N],s[670000]; ll c[160],c2[160],sum[160],sum2[160]; int main(){ int n=rd(),q=rd(),T=rd(),x,y,i,j,ps,t,tot=0; ll ans=0ll; For(i,1,n)a[i]=rd(); sort(a+1,a+n+1); For(i,2,3162)if(!f[i]) for(j=i*i;j<=10000019;j+=i)f[j]=1; For(i,2,10000019)if(!f[i])p[cnt++]=i; ps=lower_bound(p,p+cnt,a[n])-p; For(i,1,n)if((t=lower_bound(p,p+cnt,a[i])-p)<ps){ ++s[t]; if(a[i]<p[t])++c[p[t]-a[i]]; tot+=a[n]-p[ps-1]; ++c2[p[ps]-p[ps-1]]; }else{ tot+=a[n]-a[i]; if(a[i]<p[ps])++c2[p[ps]-a[i]]; } For(i,1,ps-1){ c[p[i]-p[i-1]]+=s[i-1]; s[i]+=s[i-1]; } For(i,1,154){ sum[i]=c[i]*i+sum[i-1];sum2[i]=(c2[i]+=c[i])*i+sum2[i-1]; c[i]+=c[i-1];c2[i]+=c2[i-1]; } while(q--){ x=rd()^(T*(ans&(1<<17)-1));y=rd()^(T*(ans&(1<<17)-1)); t=min(y/x,154); wt(ans=min((sum[t]+tot)*x+(c[154]-c[t])*y,sum2[t]*x+(c2[154]-c2[t])*y)); } flush(); return 0; }