zoukankan      html  css  js  c++  java
  • 2017.10.7北京清北综合强化班DAY7

    1.计数

    (count.cpp/c/pas)

    时间限制:1s

    内存限制:256MB

    【问题描述】

    给出m个数a[1],a[2],…,a[m]

    1~n中有多少数不是a[1],a[2],…,a[m]的倍数。

    【输入】

    输入文件名为count.in。

    第一行,包含两个整数:n,m

    第二行,包含m个数,表示a[1],a[2],…,a[m]

    【输出】

    输出文件名为count.out。

    输出一行,包含1个整数,表示答案

    【输入输出样例】

    count.in

    count.out

    10 2

    2 3

    3

    【数据说明】

    对于60%的数据,1<=n<=106

    对于另外20%的数据,m=2

    对于100%的数据,1<=n<=109,0<=m<=20,1<=a[i]<=109 

    题解:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int cnt,n,m,x,vis[5000000];
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&x);
            for(int j=1;j*x<=n;j++){
                if(!vis[j*x]){
                    vis[j*x]=true;
                    cnt++;
                }
            }
        }
        printf("%d
    ",n-cnt);
        return 0;
    }
    60暴力

    考试时用的map判重全T =…=

    正解:容斥原理...考试时想到了..可是当时不会容斥..

    一个区间内某个数倍数的个数=r/x-(l-1)/x,可是1--n中12既是3的倍数,又是4.6.的倍数

    会被筛掉好几次,所以答案=n/一个数-n/两个数的lcm+n/三个数的lcm.....

    #include<iostream>
    #include<cstdio>
    #define LL long long
    using namespace std;
    
    int n,m,ans,a[22];
    
    inline int read(){
        char ch=getchar();int x=0,f=1;
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    LL gcd(LL x,LL y){
        return y==0?x:gcd(y,x%y);
    }
    
    void dfs(int now,int cnt,LL lcm){
        if(lcm>n)return;//加上剪枝108ms,不加600ms 
        if(now==m+1){
            if(cnt&1)ans+=n/lcm;
            else if(cnt)ans-=n/lcm;
            return;
        }
        dfs(now+1,cnt,lcm);
        LL p=lcm/gcd(lcm,a[now])*a[now];
        dfs(now+1,cnt+1,p);
    }
    
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++)a[i]=read();
        dfs(1,0,1);
        printf("%d
    ",n-ans);
        return 0;
    }
    AC

    2.k大区间

    (kth.cpp/c/pas)

    时间限制:1s

    内存限制:256MB

    【问题描述】

    定义一个长度为奇数的区间的值为其所包含的的元素的中位数。

    现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。

    【输入】

    输入文件名为kth.in。

    第一行两个数nk

    第二行n个数。0<=每个数<231

    【输出】

    输出文件名为kth.out。

    一个数表示答案。 

    【输入输出样例】

    kth.in

    kth.out

    4 3

    3 1 2 4

    2

     

    【样例解释】

    [l,r]表示区间l~r的值

    [1,1]:3

    [2,2]:1

    [3,3]:2

    [4,4]:4

    [1,3]:2

    [2,4]:2

    【数据说明】

    对于30%的数据,1<=n<=100;

    对于60%的数据,1<=n<=300

    对于80%的数据,1<=n<=1000

    对于100%的数据,1<=n<=100000, k<=奇数区间的数 

    题目大意:定义一段奇数长度区间的值为它的中位数,求所有奇数区间值的第k大。

    题解:二分答案

    假设现在二分的答案为t,那么怎样统计比t大的区间的个数呢?设s[i]为1--i大于等于t的数的个数,

    发现,如果一个区间的中位数的大小比t大,那么s[r]-s[l-1]>(r-l+1)/2,==> 2*s[r]-r>2*s[l-1]-(l-1),

    我们用树状数组统计一下s[r]>s[l]的个数,因为r,l的奇偶性不同,要维护两个树状数组。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define LL long long
    #define maxn 100009
    using namespace std;
    
    int n,l,r,mid,ans,a[maxn],b[maxn],tree[maxn*3][3];
    LL k;
    
    void add(int pos,int p){
        if(pos<=0)return;
        for(;pos<=maxn*3;pos+=pos&(-pos))tree[pos][p]++;
    }
    
    LL getsum(int pos,int p){
        LL all=0;if(pos<=0)return 0;
        for(;pos;pos-=pos&(-pos))all+=tree[pos][p];
        return all;
    }
    
    bool check(int p){
        LL s=0;
        memset(tree,0,sizeof(tree));
        for(int i=1;i<=n;i++)b[i]=a[i]>=p?1:0,b[i]+=b[i-1];
        for(int i=1;i<=n;i++)b[i]=2*b[i]-i+n;
        add(n,0);//???
        for(int i=1;i<=n;i++){
            s+=getsum(b[i],(i&1)^1);
            add(b[i],(i&1));
        }
        return s>=k;
    }
    
    int main(){
        scanf("%d%lld",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),r=max(r,a[i]);
        while(l<=r){
            mid=(l+r)>>1;
            if(check(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    AC

    3. 区间求和

    sum.cpp/c/pas)

    时间限制:2s

    内存限制:256MB

    【问题述】

    n个数,给定一个k,求所有长度大于等于k的区间中前k大数的总和。这样就比较简单相信大家都会,所以此题要求当k=1~n的总和,即求

     

    【输入】

    输入文件名为sum.in。

    输入五个数n,a1,A,B,C。a1表示第一个数,A,B,C用来生成其余n-1个数。a(i)=(a(i-1)*A+B)mod C。1<=n<=1,000,000,0<=a1,A,B,C<=1,000,000,000

    【输出】

    输出文件名为sum.out。

    一个数表示答案,最后答案对1,000,000,007取模。

     

    【输入输出样例】

    sum.in

    sum.out

    3 3 1 1 10

    63

     

    样例解释】

    三个数为3,4,5

    K=1:[1,1]=3,[1,2]=[2,2]=4,[1,3]=[2,3]=[3,3]=5

    (表示各个区间在k=1时的答案)

    K=2:[1,2]=7,[2,3]=[1,3]=9

    K=3:[1,3]=12

    【数据说明】

    对于30%的数据,1<=n<=100

    对于60%的数据,1<=n<=300

    对于80%的数据,1<=n<=1000

    对于100%的数据,1<=n<=1000000

    题解:树状数组...不会做...

     首先我们讨论对于一个固定的区间[l,r]假设它的答案为ans,那么如果新增加一个数a[r+1],

    对于新的区间[l,r+1],a[r+1]出现的次数为小于a[r+1]的数的次数+1。

    所以我们要统计对于Ai<Aj &&i<j的个数,那么包含这两个数的区间为的个数为(n-j+1)*i,

    Aj对答案的贡献为Aj*i*(n-j+1)。当Ai>Aj时同理,倒过来处理。

    另外之前一直WA的原因是,离散化的时候应该双关键字查找,因为Ai<Aj时i<j。

    还有模少了爆Int...

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define mod 1000000007
    #define maxn 1000009
    #define LL long long
    using namespace std;
    
    LL n,ans,A,B,C,a[maxn],tree[maxn];
    typedef pair<LL,int> PII;
    PII b[maxn];
    
    void add(int x,int p){
        for(;x<=n;x+=x&(-x))tree[x]=(tree[x]+p)%mod;
    }
    
    LL getsum(int x){
        LL all=0;
        for(;x;x-=x&(-x))all=(all+tree[x])%mod;
        return all;
    }
    
    int main(){
        scanf("%lld%lld%lld%lld%lld",&n,&a[1],&A,&B,&C);
        b[1].first=a[1];b[1].second=1;
        for(int i=2;i<=n;i++){
            a[i]=(a[i-1]*A+B)%C;
            b[i].first=a[i];b[i].second=i;
        }    
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++)
         a[i]=lower_bound(b+1,b+n+1,make_pair(a[i],i))-b;
        for(int i=1;i<=n;i++){
            add(a[i],i);
            LL tmp=b[a[i]].first*1LL*(n-i+1)%mod;
            LL amp=getsum(a[i]);
            ans=(ans%mod+tmp*amp%mod)%mod;
        }
        memset(tree,0,sizeof(tree));
        for(int i=n;i>=1;i--){
            LL  tmp=(b[a[i]].first*1LL*i)%mod;
            LL  amp=getsum(a[i]);    
            ans=(ans%mod+tmp*amp%mod)%mod;
            add(a[i],n-i+1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    AC
  • 相关阅读:
    JLOI2012:时间流逝
    bzoj 5217: [Lydsy2017省队十连测]航海舰队
    bzoj 4894: 天赋
    bzoj 4870: [Shoi2017]组合数问题
    bzoj 1558: [JSOI2009]等差数列
    bzoj 4945: [Noi2017]游戏
    bzoj 2142: 礼物
    bzoj 5248: [2018多省省队联测]一双木棋
    51nod2383
    codeforces24D
  • 原文地址:https://www.cnblogs.com/zzyh/p/7649617.html
Copyright © 2011-2022 走看看