数学考试 1

45 篇文章 0 订阅
7 篇文章 0 订阅

NOIP2015模拟


这里写图片描述


一、小Y的绝对战争


【问题描述】

小Y与大黄爆发了一场绝对要胜利的战争。(原因是大黄生活作风问题)
小Y现在拥有N个城池,每个城池都有一个强大值 Wi
现在没有一条通路连接任意两个城池(通路是双向的)。
现在小Y想顺次修建若干条通路,使得每修建一条通路都连接了两个原本不连通的城池(联通的定义是两个城池之间存在一条由通路构成的路径)。
每修建一条通路 I->J,那么安全值就会增加 GcdWi,Wj)
为了确保这场战争的胜利,小Y想知道,可能的最大安全值是多少(囧)。


【输入】

输入文件名为war.in。
第一行一个正整数 N ,代表城池的个数。
接下来 N 行,每行一个正整数,代表这个城市的强大值。


【输出】

输出文件名为war.out。
一行一个整数,代表最大的安全值。


【输入样例】

4
1
2
3
4


【输出样例】

4

【数据范围】

对于 30% 的数据,保证有 n1000
对于 100% 的数据,保证有 n1000000 , 任意 W 小于等于 1000000


Solution

很恶心的题目,连Kruskal都打错了的我果断零分。
因为权值在 1 1000000 所以不同权值也最多只有 1000000 ,也就是说,可以直接从大到小枚举权值,将点合并。
对于一个权值 I ,可以取的所有点就是 I 的权值的倍数。
这样,时间复杂度就降低为 O(NlnN)
这个,时间复杂度为 O(NlnN) 请自行证明。


Code

#include <iostream>
#include <cstdio>
#include <algorithm>

#define Max(x,y) ((x)>(y)?(x):(y))
#define LL long long

using namespace std;

LL n,maxn,cnt,ans;
LL fa[1000010];

LL find(LL x){
    LL tmp=x,pre;
    while(tmp!=fa[tmp])tmp=fa[tmp];
    while(x!=tmp){
        pre=fa[x];
        fa[x]=tmp;
        x=pre;
    }
    return tmp;
}

int main(){

    freopen("war.in","r",stdin);
    freopen("war.out","w",stdout);

    scanf("%lld",&n);
    for(LL i=1;i<=n;i++){
        LL x;
        scanf("%lld",&x);
        if(fa[x]==x)ans+=x;
        fa[x]=x;
        maxn=Max(x,maxn);
    }
    for(LL i=maxn;i>=1&&cnt<n-1;i--){
        LL big=maxn/i,tmp,ft;
        bool first=true;
        for(LL j=1;j<=big;j++)if(fa[i*j]){
            if(first)tmp=i*j,ft=find(tmp),first=false;
            else{
                LL ff=find(i*j);
                if(ff==ft)continue;
                fa[ff]=ft;ans+=i;cnt++;
            }
        }
    }

    printf("%lld\n",ans);

    return 0;
}

二、小Y的数学作业


【问题描述】

小Y是个很好学的孩子。(附注:Y=yang)
最近老师总是布置给他(或者她)一些数学作业题,每道作业题就是求一个数 X 与数字 A 的最大公约数和 X 与数字 B 的最小公倍数。
这天晚上11:00,大黄到小Y家去“玩”,不小心弄翻了小Y的咖啡,结果 N 道题的数字 X 都看不见了,但是数字 A 、数字 B 与小 Y 算出来的答案都还在。
小Y很急,想问你对于每一道数学作业题,到底有多少种 X 满足已经算出的答案。


【输入】

输入文件名为homework.in。
第一行一个整数 N ,代表数学老师布置的题目数量。
接下来 N 行,每行 4 个正整数 A A1 B B1,代表 Gcd(x,A)=A1,Lcm(x,B)=B1


【输出】

输出文件名为homework.out
对于每个数学题,若存在这样的X,即输出合法的 X 的个数,否则输出 0


【输入样例】

2
41 1 96 288
95 1 37 1776


【输出样例】

6
2


【数据范围】

对于 50% 的数据,保证有 1AA1BB110000 n100
对于 100% 的数据,保证有 1AA1BB12,000,000,000 n2000


Solution

 Gcd(x,A)=A1,Lcm(x,B)=B1Gcd(xA1,AA1)=1,Gcd(B1x,B1B)=1

所以分解质因数:
对于 AA1 里有的质因子, x 的指数必须和 A1 的指数相等;
对于 BB1 里有的质因子, x 的指数必须和 B1 的指数相等。
x 的所有质因子的指数必须大于等于 A1 的指数,小于等于 B1 的指数。
对于一个质因子,若 x 的指数的上界为 a,下界为 b ,若 a<b 则无解,否则有 ba+1 种选法。
x 的指数需等于 a,且需等于 b ,而 ab,那么小Y就算错了。


Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f

using namespace std;

LL n,a,a1,b,b1;

LL prima[100],primb1[100];
LL ca1[100],prima1[100],ca[100],cb1[100],pca[100],pcb1[100],pca1[100];
LL need_b[100],need_a[100];
LL prime[1000010];
bool no_prime[1000010];
bool flagb[100],flaga[100];

inline LL in(){
    char x=getchar();
    LL ans=0;
    while(x<'0'||x>'9')x=getchar();
    while(x>='0'&&x<='9'){ans=ans*10+x-'0';x=getchar();}
    return ans;
}

void start(){
    for(LL i=2;i<=1000000;i++){
        if(!no_prime[i])prime[++prime[0]]=i;
        for(LL j=1;prime[j]*i<=1000000;j++){
            no_prime[prime[j]*i]=true;
            if(i%prime[j]==0)break;
        }
    }
}

int main(){

    freopen("homework.in","r",stdin);
    freopen("homework.out","w",stdout);

    start();

    n=in();
    while(n--){
        memset(flaga,0,sizeof flaga);memset(flagb,0,sizeof flagb);
        memset(need_b,0,sizeof need_b);memset(need_a,0,sizeof need_a);
        ca1[0]=prima1[0]=ca[0]=pca1[0]=cb1[0]=pca[0]=pcb1[0]=prima[0]=primb1[0]=0;
        LL ans=1;
        a=in();a1=in();b=in();b1=in();
        LL sqra=sqrt(a),sqra1=sqrt(a1),sqrb=sqrt(b),sqrb1=sqrt(b1);
        LL tma=a,tma1=a1,tmb=b,tmb1=b1;
        for(LL i=1;prime[i]<=sqra;i++){
            if(tma%prime[i]==0){
                prima[++prima[0]]=prime[i],ca[++ca[0]]=0,pca[++pca[0]]=1;
                while(tma%prime[i]==0){
                    ca[ca[0]]++;
                    tma/=prime[i];
                    pca[pca[0]]*=prime[i];
                }
            }
        }
        if(tma!=1){prima[++prima[0]]=pca[++pca[0]]=tma;ca[++ca[0]]=1;}
        for(LL i=1;prime[i]<=sqra1;i++){
            if(tma1%prime[i]==0)prima1[++prima1[0]]=prime[i],ca1[++ca1[0]]=0,pca1[++pca1[0]]=1;
            while(tma1%prime[i]==0){
                ca1[ca1[0]]++;
                tma1/=prime[i];
                pca1[pca1[0]]*=prime[i];
            }
        }
        if(tma1!=1){prima1[++prima1[0]]=pca1[++pca1[0]]=tma1;ca1[++ca1[0]]=1;}
        for(LL i=1;prime[i]<=sqrb1;i++){
            if(tmb1%prime[i]==0)primb1[++primb1[0]]=prime[i],cb1[++cb1[0]]=0,pcb1[++pcb1[0]]=1;
            while(tmb1%prime[i]==0){
                cb1[cb1[0]]++;
                tmb1/=prime[i];
                pcb1[pcb1[0]]*=prime[i];
            }
        }
        if(tmb1!=1){primb1[++primb1[0]]=pcb1[++pcb1[0]]=tmb1;cb1[++cb1[0]]=1;}
        for(LL i=1;i<=primb1[0];i++){
            if(b%primb1[i]!=0)need_b[i]=cb1[i];
            else if(b%pcb1[i]==0)need_b[i]=-1;
            else need_b[i]=cb1[i];
        }
        for(LL i=1;i<=prima[0];i++){
            if(a1%prima[i]!=0){need_a[i]=0;}
            else if(a1%pca[i]==0)need_a[i]=-1;
            else{
                for(LL j=1;j<=prima1[0];j++)
                    if(prima1[j]==prima[i])need_a[i]=ca1[j];
            }
        }
        for(LL i=1;i<=primb1[0];i++){
            flagb[i]=false;
            for(LL j=1;j<=prima[0];j++){
                if(primb1[i]==prima[j]){
                    flagb[i]=flaga[j]=true;
                    if(need_b[i]==-1&&need_a[j]==-1){
                        LL tttt;
                        for(LL k=1;k<=prima1[0];k++)if(prima1[k]==prima[j])tttt=ca1[k];
                        if(cb1[i]<tttt){ans=0;goto nxt;}
                        else ans=ans*(cb1[i]-tttt+1);
                    }
                    else if(need_b[i]==-1&&need_a[j]!=-1){
                        if(need_a[j]>cb1[i]){ans=0;goto nxt;}
                    }
                    else if(need_a[j]==-1&&need_b[i]!=-1){
                        LL tttt;
                        for(LL k=1;k<=prima1[0];k++)if(prima1[k]==prima[j])tttt=ca1[k];
                        if(need_b[i]<tttt){ans=0;goto nxt;}
                    }
                    else if(need_a[j]!=-1&&need_b[i]!=-1&&need_a[j]!=need_b[i]){ans=0;goto nxt;}
                    break;
                }
            }
            if(!flagb[i]){
                if(need_b[i]==-1)ans=ans*(cb1[i]+1);
            }
        }
        for(LL i=1;i<=prima[0];i++)
            if(!flaga[i]&&need_a[i]==-1){
                ans=INF;
                break;
            }
        nxt:
        printf("%lld\n",ans);
    }
}

三、小Y的智力游戏


【问题描述】

小Y最近迷上了一款智力游戏。(当然小Y还是很好学的)
这款智力游戏就是让你从 1 N N 个数中,选取若干个不相等的正整数,使得它们的乘积为一个完全平方数,同时,这个乘积也将成为你的得分。
他(或她,以后这个括号就省略了)想知道最大得分对 1000000007 的模值。


【输入】

输入文件名game.in
一行一个正整数 N ,代表数字的个数。


【输出】

输出文件名game.out
一行一个正整数,代表最大得分对 1000000007 的模值。


【输入样例】

3


【输出样例】

1


【数据范围】

对于 30% 的数据,保证有 n50
对于 60% 的数据,保证有 n1000
对于 70% 的数据,保证有 n10000
对于 80% 的数据,保证有 n100000
对于 90% 的数据,保证有 n1000000
对于 100% 的数据,保证有 n3000000


Solution

n! 唯一分解,然后将指数为奇数的质因子的指数减去一,得到的唯一分解式就是答案(想一想,为什么)。


Code

#include <iostream>
#include <cstdio>
#include <cmath>

#define Max(x,y) ((x)>(y)?(x):(y))
#define MOD 1000000007
#define LL long long

using namespace std;

LL n,ans=1;

LL prime[3000010];
bool no_prime[3000010];
LL ci[3000010];
LL first[3000010];

void work(int x){
    if(x==1)return;
    LL tmp=first[x];
    while(x%prime[tmp]==0){
        x/=prime[tmp];
        ci[tmp]++;
    }
    work(x);
}

LL power(LL x,LL y,LL p){
    if(y==0)return 1;
    if(y==1)return x%p;
    LL tmp=power(x,y/2,p);
    tmp=tmp*tmp%p;
    if(y&1)tmp=tmp*(x%p)%p;
    return tmp;
}

int main(){

    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);

    scanf("%lld",&n);
    for(LL i=2;i<=n;i++){
        if(!no_prime[i]){prime[++prime[0]]=i;first[i]=prime[0];}
        for(LL j=1;prime[j]*i<=n;j++){
            first[prime[j]*i]=j;
            no_prime[prime[j]*i]=true;
            if(i%prime[j]==0)break;
        }
    }
    for(LL i=2;i<=n;i++)work(i);
    for(LL i=1;i<=prime[0];i++){
        if(ci[i]&1)ans=ans*power(prime[i],ci[i]-1,MOD)%MOD;
        else ans=ans*power(prime[i],ci[i],MOD)%MOD;
    }
    printf("%lld\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值