清北第三套题

 

                      

【问题描述】

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

【输入格式】

第一行一个数字。

【输出格式】

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

【样例输入】

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分)
原文地址:https://www.cnblogs.com/sjymj/p/6037426.html