T1
思路1
STL中的nth_element()方法的使用
通过调用nth_element(start, start+n, end)
可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素)
并且比这个元素小的元素都排在这个元素之前
比这个元素大的元素都排在这个元素之后
但不能保证他们是有序的
代码1
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define mod 1000000000 using namespace std; void read(long long &now){ now=0;bool flag=false; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-')flag=true; c=getchar(); } while(c>='0'&&c<= '9'){ now=now*10+c-'0'; c=getchar(); } now=flag?-now:now; } inline void putout(long long x){ char c[15];int k=0; if(x<0) putchar('-'),x=-x; do{ c[++k]=x%10+48; x/=10; }while(x); while(k) putchar(c[k--]); } long long n,m,x,y,a[10000005]; long long ans; int main(){ freopen("shop.in","r",stdin); freopen("shop.out","w",stdout); read(n);read(m); read(x);read(y); a[1]=x; for(int i=2;i<=n;i++){ a[i]=(a[i-1]*y+x)%mod; } nth_element(a+1,a+m+1,a+n+1); for(int i=1;i<=m;i++)ans+=a[i]; putout(ans); return 0; }
思路2
优先队列(堆)
由于维护的堆元素元素较少(m<=100)
时间复杂度n*logm
而不是n*logn
代码2
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define mod 1000000000 using namespace std; void read(int &now){ now=0;bool flag=false; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-')flag=true; c=getchar(); } while(c>='0'&&c<= '9'){ now=now*10+c-'0'; c=getchar(); } now=flag?-now:now; } inline void putout(long long x){ char c[15];int k=0; if(x<0) putchar('-'),x=-x; do{ c[++k]=x%10+48; x/=10; }while(x); while(k) putchar(c[k--]); } int n,m,x,y; priority_queue<int>q; int main(){ freopen("shop.in","r",stdin); freopen("shop.out","w",stdout); read(n);read(m);read(x);read(y); int now=x; q.push(x); for(int i=2;i<=n;i++){ now=(1ll*now*y+x)%mod; if(q.size()<m){ q.push(now); continue; } if(now<q.top()){ q.pop(); q.push(now); } } long long ans=0; while(!q.empty()){ ans+=q.top(); q.pop(); } putout(ans); printf(" "); return 0; }
思路3
是个AC概率极大,但可能答案不对的想法,也是个很奇妙的想法
可以开数组记录哪些数出现过,并且记录出现过几次(因为可能有重复),然后从小处找够m个
这种思路我压根没想到
向来考虑的都是正确的做法,并想方设法证明正确性,而忽略了贪心策略
这是考试中的一大失误
代码3
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N=1e7+1,mod=1e9,M=1e8+1; int n,m,emp,a[N],vis[M]; long long x,y,ans; int main() { freopen("shop.in","r",stdin); freopen("shop.out","w",stdout); scanf("%d%d%I64d%I64d",&n,&m,&x,&y); a[1]=x; if(x<M)vis[x]=1; for(int i=2; i<=n; ++i) { a[i]=(y*a[i-1]+x)%mod; if(a[i]<M) ++emp,++vis[a[i]]; } if(n<=1000){ for(int i=2;i<=n;i++){ a[i]=(a[i-1]*y+x)%mod; } sort(a+1,a+n+1); for(int i=1;i<=m;i++) ans+=a[i]; }else{ if(emp<m){ sort(a+1,a+n+1); } for(int i=0; i<M; ++i) if(vis[i]) { if(m>vis[i]) { ans+=1ll*i*vis[i]; m-=vis[i]; } else { ans+=1ll*m*i; break; } } } printf("%I64d",ans); return 0; }
T2
思路
Dp
P[i][j][0]确定第i个是否消失后,二进制第j位是0的概率
P[i][j][1]确定第i个是否消失后,二进制第j位是1的概率
代码
#include<iostream> #include<cstring> #include<cstdio> #define N 100005 using namespace std; int a[N],b[N]; double c[N]; int f[N][33]; double p[N][33][2]; int n; void change(){ for(int i=1;i<=n;i++){ int now=b[i]; int cnt=0; while(now){ f[i][++cnt]=now%2; now/=2; } } } int main(){ freopen("exp.in","r",stdin); freopen("exp.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int j=1;j<=n;j++) scanf("%d",&b[j]); for(int i=1;i<=n;i++) scanf("%lf",&c[i]); change(); for(int i=1;i<=31;i++){ p[0][i][0]=1; p[0][i][1]=0; } for(int j=1;j<=31;j++){ for(int i=1;i<=n;i++){ if(a[i]==0){ p[i][j][0]=f[i][j]?(p[i-1][j][0]):(p[i-1][j][1]*(1.0-c[i])+p[i-1][j][0]); p[i][j][1]=f[i][j]?(p[i-1][j][1]):(p[i-1][j][1]*c[i]); }else if(a[i]==1){ p[i][j][0]=f[i][j]?(p[i-1][j][0]*c[i]):p[i-1][j][0]; p[i][j][1]=f[i][j]?(p[i-1][j][1]*c[i]+(1.0-c[i])):p[i-1][j][1]; }else if(a[i]==2){ p[i][j][0]=f[i][j]?(p[i-1][j][1]*(1.0-c[i])+p[i-1][j][0]*c[i]):(p[i-1][j][0]); p[i][j][1]=f[i][j]?(p[i-1][j][0]*(1.0-c[i])+p[i-1][j][1]*c[i]):(p[i-1][j][1]); } } } double answer=0.0; for(int i=31;i>=1;i--){ answer=answer*2.0+p[n][i][1]; } printf("%.1f ",answer); return 0; }
这里有更简洁的做法