10.16模拟赛

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("\n");
    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\n",answer);
    return 0;
}

这里有更简洁的做法

https://www.cnblogs.com/L-Memory/p/9799878.html

 

posted @ 2018-10-17 07:41  冬猫  阅读(93)  评论(0编辑  收藏  举报