zoukankan      html  css  js  c++  java
  • 9.14模拟赛

    T1  COGS2524评测

    题目描述

    1-N1N中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。

    输入输出格式

    输入格式:

     

    第一行一个数字NN。

     

    输出格式:

     

    一行一个整数代表答案对100000007100000007取模之后的答案。

     

    输入输出样例

    输入样例#1:
    7
    输出样例#1:
    144
    

    说明

    对于20\%20%的数据,1 leq N leq 1001N100。

    对于50\%50%的数据,1 leq N leq 50001N5000。

    对于70\%70%的数据,1 leq N leq 10^51N105​​。

    对于100\%100%的数据,1 leq N leq 5 imes 10^61N5×106​​。

    题解:线性筛+快速幂

    如果将完全平方数分解质因数,那么质因数的次数一定都是偶数次的。

    将1--n中的质数筛出来,然后找每个质数在1--n中出现了多少次,如果是

    偶数次直接贡献答案,奇数次-1贡献答案,因为奇数次要-1,所以丢弃这个

    质数本身,不会出现一个数只取了一部分。怎样求1--n中因数x出现的次数呢,

    举个例子,1--81中3出现的次数是 81/3+27/3+9/3+3/3=40。

    先了解是这么个方法。

    假如求1--30中因数3出现的次数,

    3          6         9        12        15         18       21      24        27      30

    3*1     3*2      3*3      3*4      3*5      3*3*2    3*7    3*8      3*3*3   3*10

    表是上下对应的。

    数一数3出现了14次。

    1--30中能整除一个3的个数有 30/3=10 ,是上面全部的数

    1--30中能整除两个3的个数有 30/(3*3) =3 ,是9 18 27

    1--30中能整除三个3的个数有  30/(3*3*3) =1,是27,

    加起来为 30/3+30/(3*3)+30/(3*3*3)=14,

    变一下也就是 30/3+9/3+3/3=14。

    上面讲完 ,对于本题讲个例子,求1--6能组成的最大的完全平方数。

    1      2      3      4        5       6       

    1    1*2   1*3    2*2    1*5   2*3   

    其中2出现 5次 3出现2次 5出现一次,奇数次-1,只剩下2^4和3^2,所以答案为2^4*3^2

    又理解了一遍 if(i%prime[j]==0)break;如果i是prime[j]的倍数,也就是i=k*prime[j],那么i*prime[j+1]

    这个数是下一个被筛去的合数,i*prime[j]=k*prime[j]*prime[j+1]=gg*prime[j]会被prime[j]筛去

    保证了O(n)的复杂度。

    注意:没开Long long 一直卡 =n=

    代码:

    #include<iostream>
    #include<cstdio>
    #define mod 100000007
    using namespace std;
    
    int n,js;
    long long ans=1;
    int prime[5000005],check[5000005];
    
    void Prime(){
        check[1]=1;
        for(int i=2;i<=n;i++){
            if(!check[i])prime[++js]=i;
            for(int j=1;j<=js&&i*prime[j]<=n;j++){
                check[i*prime[j]]=1;
                if(i%prime[j]==0)break;
            }
        }
    }
    
    int count(int x){
        int tmp=n,res=0;
        while(tmp){
            tmp/=x;
            res+=tmp;
        }
        return res;
    }
    
    long long ksm(int x,int y){
        long long now=x,res=1;
        while(y){
            if(y&1)res=1LL*res*now%mod;
            now=now*now%mod;
            y>>=1;
        }
        return res%mod;
    }
    int main(){
        scanf("%d",&n);
        Prime();
        for(int i=1;i<=n;i++){
            if(!check[i]){
                int k=count(i);
                ans=ans*ksm(i,k/2*2)%mod;
                
            }
        }
        cout<<ans;
        return 0;
    }

     

    T2

    题目描述

    NN个数,随机选择一段区间,如果这段区间的所有数的平均值在[l,r][l,r]中则你比较厉害。求你比较厉害的概率。

    输入输出格式

    输入格式:

     

    第一行有三个数N,l,rN,l,r,含义如上描述。

    接下来一行有NN个数代表每一个数的值。

     

    输出格式:

     

    输出一行一个分数Large frac{a}{b}ba​​代表答案,其中a,ba,b互质。如果答案为整数则直接输出该整数即可。

     

    输入输出样例

    输入样例#1:
    4 2 3
    3 1 2 4
    输出样例#1:
    7/10
    输入样例#2:
    4 1 4
    3 1 2 4
    输出样例#2:
    1

    说明

    对于30\%30%的数据,1 leq n leq 10^41n104​​。

    对于60\%60%的数据,1 leq n leq 10^51n105​​。

    对于100\%100%的数据,1 leq n leq 5 imes 10^5,0 < l leq r leq 1001n5×105​​,0<lr100。

    题目大意:求一段区间内有多少个子区间的平均值在[l,r]范围内。

    题解:

    暴力10分,前缀和+枚举,也可以递推 注意分母为0 还好随便输入几个数测发现re

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int n,l,r,ans;
    int f[2],sum[500008],dp[500005];
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    int gcd(int x,int y){
        return y==0?x:gcd(y,x%y);
    }
    
    int main(){
        freopen("jian.in","r",stdin);
        freopen("jian.out","w",stdout);
        n=read();l=read();r=read();
        for(int i=1;i<=n;i++){
            int x;x=read();
            f[1]=f[0]+i;
            f[0]=f[1];
            sum[i]=sum[i-1]+x;
        }
    /*    for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(j+i-1>n)break;
                double k=double((sum[j+i-1]-sum[j-1])/i);
                if(k>=l&&k<=r)ans++;
            }
        }
        if(ans==f[0])printf("1
    ");
        else if(f[0]%ans==0)printf("1/%d",f[0]/ans);
        else {
            int g=gcd(ans,f[0]);
            printf("%d/%d",ans/g,f[0]/g);
        }
        */
        for(int i=1;i<=n;i++){
           dp[i]=dp[i-1];
            for(int j=1;j<=i;j++){
                double k=(sum[i]-sum[j-1])/(i-j+1);
                dp[i]+=(k>=l&&k<=r);
            }
        }
        if(f[0]==dp[n])printf("1
    ");
        else
        if(dp[n]==0)printf("0
    ");
        else
        if(f[0]%dp[n]==0){
            printf("1/%d
    ",f[0]/dp[n]);
        }else{
            int g=gcd(dp[n],f[0]);
            printf("%d/%d
    ",dp[n]/g,f[0]/g);
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    正解:逆序对....

    n个数的和为An,如果区间[1,n]的平均数满足在区间[l,r]的范围内,那么n*l≤An≤n*r,

    那么将这n 个数都减去l,并求减去的数的前缀和,那么对于区间[a,b]满足平均值属于[l,r]

    的条件是sa-sb>=0 ,那么只要sa-sb<0,即sa<sb,就不满足条件。这就是逆序对....

    同理当n个数都减去r,并求前缀和,如果sa-sb>0,不满足条件,即sa>sb,将区间翻转

    还是求逆序对个数。补集思想,全部的情况n*(n+1)-不满足的个数为满足的个数。

    reverse 函数翻转整个区间 线性的时间复杂度 涨姿势

    太神辣 orz

    代码

     80

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    long long n,l,r;
    long long res,ans;
    long long a[5000005],b[5000005];
    long long sum[5000005];
    
    long long gcd(long long x,long long y){
        return y==0?x:gcd(y,x%y);
    }
    
    void merge(int lx,int lr){
        if(lx==lr)return;
        long long  mid=(lx+lr)>>1;
        merge(lx,mid);merge(mid+1,lr);
        int ll=lx,k=lx,rr=mid+1;
        while(ll<=mid&&rr<=lr){
            if(sum[ll]<=sum[rr]){
                b[k++]=sum[ll++];
            }else{
                ans+=mid-ll+1;
                b[k++]=sum[rr++];
            }
        }
        while(ll<=mid)b[k++]=sum[ll++];
        while(rr<=lr)b[k++]=sum[rr++];
        for(int i=lx;i<=lr;i++)sum[i]=b[i];
    }
    
    int main(){
        scanf("%lld%lld%lld",&n,&l,&r);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++){sum[i]=sum[i-1]+a[i]-l;}
        ans=0;merge(0,n);res+=ans;ans=0;
        for(int i=1;i<=n;i++){sum[i]=sum[i-1]+a[i]-r;}
        reverse(sum+1,sum+n+1);merge(1,n+1);res+=ans;
        long long mu=1LL*n*(n+1)/2,zi=mu-res;
        if(mu==zi)printf("1
    ");
        else if(zi==0){printf("0
    ");}
        else {long long k=gcd(mu,zi);cout<<zi/k<<"/"<<mu/k<<endl;}
        return 0;
    }

    AC

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define name "jian"
    #define ll long long
    #ifdef unix
    #define LL "%lld"
    #else
    #define LL "%I64d"
    #endif
    using namespace std;
    const int N=1e6+10;
    int n,L,R,a[N],b[N];
    ll fz,fm,gy,ans,s[N],c[N];
    inline const int read(){
        register int x=0,f=1;
        register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    void binary_chop(int l,int r){
        if(l==r) return ;
        int mid=l+r>>1;
        binary_chop(l,mid);binary_chop(mid+1,r);
        int p=l,q=l,j=mid+1;
        while(p<=mid&&j<=r){
            if(s[p]>s[j]){
                ans+=mid-p+1;
                c[q++]=s[j++];
            }
            else{
                c[q++]=s[p++];
            }
        }
        while(p<=mid) c[q++]=s[p++];
        while(j<=r) c[q++]=s[j++];
        for(int i=l;i<=r;i++) s[i]=c[i];
    }
    int main(){
        freopen(name".in","r",stdin);
        freopen(name".out","w",stdout);
        n=read();L=read();R=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++) b[i]=a[i]-L;
        for(int i=1;i<=n+1;i++) s[i]=s[i-1]+b[i-1];
        binary_chop(1,n+1);fz+=ans;
        memset(s,0,sizeof s);ans=0;
        for(int i=1;i<=n;i++) b[i]=a[i]-R;
        for(int i=1;i<=n+1;i++) s[i]=s[i-1]+b[i-1];
        reverse(s+1,s+n+2);
        binary_chop(1,n+1);fz+=ans;
        fm=(ll)n*(n+1)/2;
        fz=fm-fz;
        gy=__gcd(fz,fm);
        fz/=gy;fm/=gy;
        if(fm==1) printf(LL"
    ",fz);
        else printf(LL "/" LL,fz,fm);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

     

    T3

    题目描述

    m imes mm×m的方阵上有nn棵葱,你要修一些栅栏把它们围起来。一个栅栏是一段沿着网格建造的封闭图形(即要围成一圈)。各个栅栏之间应该不相交、不重叠且互相不包含。如果你最多修kk个栅栏,那么所有栅栏的长度之和最小是多少?

    输入输出格式

    输入格式:

     

    第一行三个整数m,k,nm,k,n。

    接下来nn行每行两个整数x,yx,y代表某棵葱的位置。

     

    输出格式:

     

    一行一个整数代表答案。

     

    输入输出样例

    输入样例#1:
    6 1 4
    1 3
    4 2
    4 4
    6 4
    输出样例#1:
    18
    输入样例#2:
    6 2 4
    1 3
    4 2
    4 4
    6 4
    输出样例#2:
    16

    说明

    对于10\%10%的数据,k=1k=1。

    对于30\%30%的数据,k leq 2k2。

    对于60\%60%的数据,n leq 10n10。

    对于100\%100%的数据,1 leq k leq n leq 16,m leq 10001kn16,m1000。

    题目大意:矩形上有几根葱,用不重叠 不相交 不包含的栅栏围住 求栅栏的最小周长。

    栅栏必须是封闭的。

    题解:搜索+剪枝

    代码:

    95卡时

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<ctime>
    #define maxn 1001
    #define minn -1
    using namespace std;
    int m,k,n,ans=0x7fffffff,p;
    int g[20][20];
    int cx[20],cy[20];
    int dhx[20],dhd[20],dlx[20],dld[20];
    int judge(int h[][20])
    {
          int s=0;
          for(int i=1;i<=k;i++)
                 if(dhd[i]!=-1)
                    s+=(dhd[i]-dhx[i]+dld[i]-dlx[i]+2)*2;    
          return s; 
    }
    void change(int x,int d)
    {
        dhx[d]=min(dhx[d],cx[x]);
        dhd[d]=max(dhd[d],cx[x]);
        dlx[d]=min(dlx[d],cy[x]);
        dld[d]=max(dld[d],cy[x]);
     } 
    void dfs(int x,int a[][20])
    {
        if(clock()>1950)
        {
            printf("%d",ans);
            fclose(stdin);fclose(stdout);
            exit(0);
        }
        p=judge(a); 
        if(p>=ans) return;
        if(x==n+1)
         {
            if(p<ans) ans=p;
            return; 
         }
        for(int i=1;i<=k;i++)
         {
             a[i][++a[i][0]]=x;
             int khx=dhx[i],khd=dhd[i],klx=dlx[i],kld=dld[i];
            change(x,i);
            dfs(x+1,a);
            a[i][a[i][0]--]=0;
            dhx[i]=khx;dhd[i]=khd;dlx[i]=klx;dld[i]=kld;
         }
    } 
    int main()
    {
        freopen("dan.in","r",stdin);
        freopen("dan.out","w",stdout);
        scanf("%d%d%d",&m,&k,&n);
            for(int i=1;i<=k;i++)
        {
            dhx[i]=dlx[i]=1001;
            dhd[i]=dld[i]=-1;
        }
        for(int i=1;i<=n;i++)
        scanf("%d%d",&cx[i],&cy[i]);
        dfs(1,g);
        printf("%d",ans);
    } 
    
    

    AC

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int m,k,n,x[20],y[20],f[17][1<<16],cost[1<<16],s[20],ans;
    void dfs(int now,int cnt,int res)
    {
        if (now==n)
        {
            if (res<ans) ans=res;
            return;
        }
        if (res+(k-cnt)*4>=ans) return;
        for (int a=1;a<=cnt;a++)
        {
            int pres=s[a];
            s[a]|=(1<<now);
            dfs(now+1,cnt,res-cost[pres]+cost[s[a]]);
            s[a]^=(1<<now);
        }
        if (cnt<k)
        {
            cnt++;
            s[cnt]=(1<<now);
            dfs(now+1,cnt,res+4);
        }
    }
    int main()
    {
        freopen("dan.in","r",stdin);
        freopen("dan.out","w",stdout);
        scanf("%d%d%d",&m,&k,&n);
        for (int a=0;a<n;a++)
            scanf("%d%d",&x[a],&y[a]);
        if (n<=14)
        {
            memset(f,0x3f,sizeof(f));
            for (int a=1;a<(1<<n);a++)
            {
                int sx=1001,mx=-1,sy=1001,my=-1;
                for (int b=0;b<n;b++)
                    if ((a>>b)&1)
                    {
                        if (x[b]<sx) sx=x[b];
                        if (x[b]>mx) mx=x[b];
                        if (y[b]<sy) sy=y[b];
                        if (y[b]>my) my=y[b];
                    }
                f[1][a]=(mx-sx+1)*2+(my-sy+1)*2;
            }
            for (int a=2;a<=k;a++)
                for (int b=0;b<(1<<n);b++)
                    for (int c=b-1;c;c=(c-1)&b)
                        f[a][b]=min(f[a][b],f[a-1][c]+f[1][b^c]);
            int ans=f[1][(1<<n)-1];
            for (int a=2;a<=k;a++)
                ans=min(ans,f[a][(1<<n)-1]);
            printf("%d
    ",ans);
        }
        else
        {
            ans=4000;
            for (int a=1;a<(1<<n);a++)
            {
                int sx=1001,mx=-1,sy=1001,my=-1;
                for (int b=0;b<n;b++)
                    if ((a>>b)&1)
                    {
                        if (x[b]<sx) sx=x[b];
                        if (x[b]>mx) mx=x[b];
                        if (y[b]<sy) sy=y[b];
                        if (y[b]>my) my=y[b];
                    }
                cost[a]=(mx-sx+1)*2+(my-sy+1)*2;
            }
            dfs(0,0,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    打开LogCat以便查看日志
    sql语句优化
    IIS部署说明
    VM上Hadoop3.1伪分布式模式搭建
    C# 程序结构
    CSS笔记1:属性定位
    VS2013 添加控制台程序
    布局 Layout
    [游泳] 游泳学习课程
    "12306"台前幕后:五年利益之争 仓促上线
  • 原文地址:https://www.cnblogs.com/zzyh/p/7523544.html
Copyright © 2011-2022 走看看