zoukankan      html  css  js  c++  java
  • 清北第三套题

     

                          

    【问题描述】

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

    【输入格式】

    第一行一个数字。

    【输出格式】

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

    【样例输入】

    7

    【样例输出】

    144

    【样例解释】

    但是塔外面有东西。

    【数据规模与约定】

    对于20%的数据,1<=N<=100。

    对于50%的数据,1<=N<=5000。

    对于70%的数据,1<=N<=10^5。      

    对于100%的数据,1<=N<=5*10^6。

     

    题解:可以将n的阶乘质因数分解,然后若质因数的指数为奇数则指数减1乘进答案。若为偶数直接乘进答案。因为只有当质因数的指数是偶数时,才能开方开出来,当质因数指数是奇数时,可以除以一个这个质因数,就可以开出来了。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define N 5000100
    using namespace std;
    const int M=100000007;
    int n,num(0);
    long long ans(1);
    int ss[N],zs[N]={0};
    bool f[N]={0};
    int oula()//欧拉筛法 
    {
       for (int i=2;i<=n;i++)
         {
             if (!f[i]) ss[++num]=i;
             for (int j=1;j<=num,ss[j]*i<=n;j++) 
               {
                    f[ss[j]*i]=1;
                    if (!(i%ss[j])) break;
               }
         }
    }
    long long jc(long long p,long long k)//快速幂 
    {
        long long ki=1;
        while (k)
          {
               if (k%2) ki=ki*p%M;
               p=p*p%M;
               k/=2;
          }
        return ki;
    }
    int main()
    {
        freopen("hao.in","r",stdin);
        freopen("hao.out","w",stdout);
        scanf("%d",&n);
        oula();
        for (int i=1;i<=num;i++)//n的阶乘质因数分解 
          {
               int k=n;
               while (k)
                 {
                    zs[i]+=k/ss[i];
                  k/=ss[i];
               }
          }
        for (int i=1;i<=num;i++)
          {
               if (zs[i]%2) ans=ans*jc(ss[i],zs[i]-1)%M;
                else ans=ans*jc(ss[i],zs[i])%M;
          }
        cout<<ans<<endl;
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    质因数分解

                    

    【问题描述】

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

    【输入格式】

    第一行有三个数,含义如上描述。

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

    【输出格式】

    输出一行一个分数代表答案,其中互质。如果答案为整数则直接输出该整数即可。

    【样例输入1】

    4 2 3

    3 1 2 4

    【样例输出1】

    7/10

    【样例输入2】

    4 1 4

    3 1 2 4

    【样例输出2】

    1

    【样例解释】

    塔外面有棵树。

    【数据规模与约定】

    对于30%的数据,1<=N<=10^4。

    对于60%的数据,1<=N<=10^5。

    对于100%的数据,1<=N<=5*10^5,0<l<=r<=100.

    题解:可以先求出平均值小于l的区间的个数与平均值大于r的区间的个数和,然后用总的区间总数减去不满足条件的区间数就是满足的区间总数。

             求平均值小于l的区间个数时,可以先求出a[i]-l的前缀和li[i],那么此时小于0的区间即为小于l的区间。由于区间a[i]~a[j]的值是li[j]-li[i-1],要想满足区间小于0,则li[i-1]>li[j],那么这就是求li数组的逆序对数。要注意加上单独一个数<0的情况。

            求平均值大于r的区间个数时类似,但是求得是r-a[i]的前缀和。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    #define N 500100
    #define ll long long
    using namespace std;
    ll n,l,r,ans(0),fz,fm; //注意开long long ,不然会爆掉 
    ll l1[N]={0},b[N]={0},a[N]={0};
    ll gcd(ll x,ll y)
    {
        if (y==0) return x;
        else return gcd(y,x%y);
    }
    void xx()
    {
        memset(b,0,sizeof(b));
        memset(l1,0,sizeof(l1));
        ans=0;
    }
    void msort(ll x,ll y)
    {
        if (x>=y) return ;
        ll mid=(x+y)>>1;
        msort(x,mid);
        msort(mid+1,y);
        ll i=x,j=mid+1,t=x-1;
        while (i<=mid&&j<=y)
          {
               if (l1[i]<=l1[j]) b[++t]=l1[i++];
               else
               {
                   ans+=mid-i+1;
                 b[++t]=l1[j++];    
             }
           } 
         while (i<=mid) b[++t]=l1[i++];
         while (j<=y) b[++t]=l1[j++];
         for (i=x;i<=y;i++) l1[i]=b[i];
         return ;
    }
    int main()
    {
        freopen("jian.in","r",stdin);
        freopen("jian.out","w",stdout);
        cin>>n>>l>>r;
        for (ll i=1;i<=n;i++) scanf("%lld",&a[i]);
        for (ll i=1;i<=n;i++)     l1[i]=l1[i-1]+a[i]-l;
        for (ll i=1;i<=n;i++)//不要忘记判断单独一个数。- -找了好长好长时间错误。 
          if (l1[i]<0) ans++;
        msort(1,n);    
        fz=ans;
        xx();
        for (ll i=1;i<=n;i++) l1[i]=l1[i-1]+r-a[i];
        for (ll i=1;i<=n;i++)
          if (l1[i]<0) ans++;
        msort(1,n);
        fz+=ans;
        fm=(n*(n+1)/2);    //所有的组合方式 
        fz=fm-fz;
        if (fz==0) printf("0
    ");
        else if (fz==fm) 
        {
              printf("1
    ");
        }
        else
          {
               ll ki=gcd(fz,fm);
               fz/=ki;
               fm/=ki;
               cout<<fz<<'/';
               cout<<fm;
          }
        fclose(stdin);
        fclose(stdout);
        
        return 0;
    }
    求逆序对

                                  

    【问题描述】

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

    【输入格式】

    第一行三个整数。

    接下来行每行两个整数代表某棵葱的位置。

    【输出格式】

    一行一个整数代表答案。

    【样例输入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%的数据,k=1。

    对于30%的数据,k<=2。

    对于60%的数据,n<=10。

    对于100%的数据,1<=k<=n<=16,m<=1000。

     

     

     

    题解:暴力搜索。有25分会超时,此时用zhx教的方法,用clock()函数判断一下运行时间,超过一定时间直接输出答案,停止搜索。可以骗取20分。

     

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<ctime>
    #include<algorithm>
    #define N 20
    #define ll long long 
    using namespace std;
    int m,k,n,ans=0x7fffffff/3;
    int x1[N],x2[N],y1[N],y2[N];
    int x[N],y[N];
    void xx()
    {
        memset(x1,127/3,sizeof(x1));
        memset(y1,127/3,sizeof(y1));
    }
    void dfs(int now)//枚举每跟葱 
    {
        if (clock()>1950) //超过时间限制,直接输出 
        {
               printf("%d
    ",ans);
               exit(0);
         }
        int mx=0;
        for (int i=1;i<=k;i++)
          {
              if (x1[i]==x1[0]) continue;
              mx+=(x2[i]-x1[i]+1+y2[i]-y1[i]+1)*2;
          }
        if (mx>=ans) return ;
        if (now==n+1)
          {
               int mx=0;
               for (int i=1;i<=k;i++)
                 {
                    if (x1[i]==x1[0]) continue;
                  mx+=(x2[i]-x1[i]+1+y2[i]-y1[i]+1)*2;    
               }
            ans=min(ans,mx);
            return ;
          }
        for (int i=1;i<=k;i++)
          {
               int a=x1[i],b=x2[i],c=y1[i],d=y2[i];
               x1[i]=min(x1[i],x[now]);
               x2[i]=max(x2[i],x[now]);
               y1[i]=min(y1[i],y[now]);
               y2[i]=max(y2[i],y[now]);
               dfs(now+1);
               x1[i]=a;x2[i]=b;y1[i]=c;y2[i]=d;
          }
    }
    int main()
    {
        freopen("dan.in","r",stdin);
        freopen("dan.out","w",stdout);
        
        xx();
        scanf("%d%d%d",&m,&k,&n);
        for (int i=1;i<=n;i++)
          scanf("%d%d",&x[i],&y[i]);
        dfs(1);
        printf("%d
    ",ans);
        
        fclose(stdin);
        fclose(stdout);
        
        return 0;
    }
    暴搜(95分)
  • 相关阅读:
    判断arm立即数是否合法的小程序
    一个操作系统的实现:关于ALIGN的若干解释
    一个郁闷的C语言小问题
    test
    浮点数的比较
    一个操作系统的实现:Descriptor 3详解
    一个操作系统的实现:关于CPL、RPL、DPL
    C99可变长数组VLA详解
    SVProgressHUD 用法
    IOS CALayer 详解
  • 原文地址:https://www.cnblogs.com/sjymj/p/6037426.html
Copyright © 2011-2022 走看看