2018.7.21 绍兴一中模拟赛 解题报告(更新ing)

成绩:100+60+50=210(考得一般,差不多刚好达到基础分)

T1:数学(math)

80分做法:

很简单,直接暴力枚举 1... m 间的每一个数,计算其与 n g c d ,并将结果相乘,即可得到答案。

这样的做法接近于 O ( n ) 。因此只能得80分,并不能AC。

代码如下:

#include<bits/stdc++.h>
#define YKH 1000000007
#define LL long long
using namespace std;
LL n,m,ans=1;
inline char tc()
{
    static char ff[100000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0;char ch;
    while(!isdigit(ch=tc()));
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline LL gcd(LL x,LL y)//求最大公因数
{
    return y?gcd(y,x%y):x;
}
int main()
{
    freopen("math.in","r",stdin),freopen("math_.out","w",stdout);
    register LL i;LL flag=2;
    read(n),read(m);
    for(i=1;i<=m;++i) (ans*=gcd(i,n))%=YKH;//暴力枚举
    return write(ans),0;
}
满分做法:

满分做法其实也并不难。

我们可以枚举n的每一个质因子(这只需要 O ( n ) 的时间),然后计算出在 1... m 的范围中有多少个数含有这个质因子(可以直接用 m 除以该质因子),然后快速幂求出这些因子的乘积即可。

我的代码中主要是用除余法来筛质因子,虽然这里用的并不标准,可能依然会有一部分的合数,但是在这题中并不影响答案,还能打打提高效率。

代码如下:

#include<bits/stdc++.h>
#define YKH 1000000007
#define LL long long
using namespace std;
LL n,m,ans=1;
inline char tc()
{
    static char ff[100000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0;char ch;
    while(!isdigit(ch=tc()));
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline bool Is_Prime(LL x)//判断n是否已是质数,若是,则可直接计算出答案
{
    if(x<=1) return false;
    for(register LL i=2;i*i<=x;++i) if(!(x%i)) return false;
    return true;
}
inline LL quick_pow(LL x,LL y)//快速幂,大大减少计算乘积的时间
{
    LL res=1;
    while(y)
    {
        if(y&1) (res*=x)%=YKH;
        (x*=x)%=YKH,y>>=1;
    }
    return res;
}
inline void doing(LL val)
{
    LL x=val;//用一个变量来记录一下当前正在操作的数
    while(!(n%x)) (ans*=quick_pow(val,m/x))%=YKH,x*=val;//判断n中是否含有多个该因子,对于每一个该因子,用快速幂计算出其乘积
    n/=x/val;//将这个质因子从n中除去
    if(Is_Prime(n))//判断当前的n是否已是质数
    {
        write(ans*quick_pow(n,m/n)%YKH);//输出最终答案
        exit(0);//退出整个程序
    }
}
int main()
{
    freopen("math.in","r",stdin),freopen("math.out","w",stdout);
    register LL i;LL flag=2;//flag表示i每次增加的数,使i始终可以表示为6n±1的形式,且不遗漏
    read(n),read(m),doing(2),doing(3);//单独处理2,3两个质数
    if(Is_Prime(n)) return write(ans*quick_pow(n,m/n)%YKH),0;
    for(i=5;i<=m&&n>1;i+=flag,flag=6-flag) doing(i);//枚举每一个质数(6n±1不一定是质数,但大于2和3的质数一定可以用这种形式来表示)
    return write(ans),0;
}

T2:序列求和(magic)

60分做法:

直接 O ( n 2 ) 枚举序列中的每一个区间,并在枚举的同时不断更新该区间的最大值和异或值,从而求出每一段区间的答案,将其累加就是最终的答案。

代码如下:

#include<bits/stdc++.h>
#define YKH 1000000007
#define LL long long
#define N 100000
using namespace std;
LL n,ans=0,a[N+5],s[N+5];
inline char tc()
{
    static char ff[100000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0;char ch;
    while(!isdigit(ch=tc()));
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int main()
{
    freopen("magic.in","r",stdin),freopen("magic.out","w",stdout);
    register LL i,j;
    for(read(n),i=1;i<=n;read(a[i]),s[i]=s[i-1]^a[i],++i);//用s[]数组累计异或值
    for(i=1;i<=n;++i)
    {
        LL MAX=0;//用一个变量来记录每个区间的最大值
        for(j=i;j<=n;++j)
            MAX=max(MAX,a[j]),(ans+=MAX*(s[j]^s[i-1]))%=YKH;//枚举区间,更新最大值,求出答案
    }
    return write(ans),0;
}
满分做法:

这题暂时还没有改满,等改满后再更新该部分的题解。

T3:DxxA(dxxa)

50分做法:

赤裸裸的暴力,代码如下:

#include<bits/stdc++.h>
#define LL long long
#define N 500000
using namespace std;
LL n,A,B,C,ans=0,a[N+5],b[N+5],c[N+5];
inline char tc()
{
    static char ff[100000],*A=ff,*B=ff;
    return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0;char ch;
    while(!isdigit(ch=tc()));
    while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int main()
{
    freopen("dxxa.in","r",stdin),freopen("dxxa.out","w",stdout);
    register LL i,j,k;
    for(read(n),read(A),read(B),read(C),i=1;i<=n;read(a[i]),read(b[i]),read(c[i++]));
    for(i=1;i<=A;++i)//暴力枚举A的大小
    {
        for(j=1;j<=B;++j)//暴力枚举B的大小
        {
            LL ok=1,Min=1;
            for(k=1;k<=n;++k)//枚举每一张卡牌,得出最小的C
            {
                LL flag=(i<=a[k]?0:1)+(j<=b[k]?0:1);//计算A和B中有几个不大于这张卡牌
                if(!flag||(flag==1&&c[k]==C))//如果无论如何都不可能有两个值大于当前卡牌的对应值,说明当前A和B的组合不合法
                {
                    ok=0;
                    break;
                }
                if(flag==1) Min=max(Min,c[k]+1);//否则更新C的最小值
            }
            if(ok) ans+=C-Min+1;//更新答案
        }   
    }
    return write(ans),0;
}
满分做法:

这题暂时还没有改满,等改满后再更新该部分的题解。

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/81151392
今日推荐