【数学】test20170304

【小 Y 的智力游戏】(Game.pas/c/cpp Time:1s Memory:256M)
【问题描述】
  小 Y 最近迷上了一款智力游戏。(当然小 Y 还是很好学的)这款智力游戏就是让你从 1 到 N 这 N 个数中,选取若干个不相等的正整数,使得它们的乘积为一个完全平方数,同时,这个乘积也将成为你的得分。他(或她,以后这个括号就省略了)想知道最大得分对 1000000007 的模值。
【输入】
  输入文件名 game.in 一行一个正整数 N,代表数字的个数。
【输出】
  输出文件名 game.out 一行一个正整数,代表最大得分对 1000000007 的模值。
【输入输出样例】
  Game.in  Game.out
  3      1
【数据范围】
  对于 30%的数据,保证有 n≤50。
  对于 60%的数据,保证有 n≤1000。
  对于 70%的数据,保证有 n≤10000。
  对于 80%的数据,保证有 n≤100000。
  对于 90%的数据,保证有 n≤1000000。
  对于 100%的数据,保证有 n≤3000000。

【Analysis】

  将1~n逐个分解质因数(等效于分解n!),若质因子指数为偶,直接乘,否则指数-1再乘,求n!中质数k的次数s(k)=n/k+n/(k^2)+n/(k^3)+......

【code】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int A = 3e6+10, mod = 1e9+7;
 7 
 8 int n,s;
 9 int p[A],ex[A],sum[A];
10 unsigned long long ans=1,x,k,y;
11 
12 int power(int a,int b)
13 {
14     x=a;k=1;
15     while(b)
16     {
17         if(b&1)k=(k*x)%mod;
18         x=(x*x)%mod;
19         b>>=1;
20     }
21     return k;
22 }
23 
24 void prime()
25 {
26     for(int i=2;i<=n;++i)
27     {
28         if(!ex[i])p[++s]=i;
29         for(int j=1;j<=s&&p[j]*i<=n;++j)
30         {
31             ex[p[j]*i]=1;
32             if(i%p[j]==0)break;
33         }    
34     }
35 }
36 
37 void calc(int n,int p,int &s)
38 {
39     y=p;
40     while(y<=n)s+=(n/y),y*=p;
41 }
42 
43 int main()
44 {
45     freopen("game.in","r",stdin);
46     freopen("game.out","w",stdout);
47     scanf("%d",&n);
48     prime();
49     for(int i=1;i<=s;++i)calc(n,p[i],sum[i]);
50     for(int j=1;j<=s;++j)
51         if(sum[j])
52         {
53             if(sum[j]%2==1)--sum[j];
54             if(sum[j])ans=(ans*power(p[j],sum[j]))%mod;
55         }
56     printf("%llu\n",ans);
57     return 0;
58 }

 

【小 Y 的绝对战争】(War.pas/c/cpp Time:1s Memory:256M)
【问题描述】
  小 Y 与大黄爆发了一场绝对要胜利的战争。(原因是大黄生活作风问题)小 Y 现在拥有 N 个城池,每个城池都有一个强大值 Wi。现在没有一条通路连接任意两个城池(通路是双向的)。现在小 Y 想顺次修建若干条通路,使得每修建一条通路都连接了两个原本不连通的城池(联通的定义是两个城池之间存在一条由通路构成的路径)。每修建一条通路 IJ,那么安全值就会增加 Gcd ( Wi,Wj)。为了确保这场战争的胜利,小 Y 想知道,可能的最大安全值是多少(囧)。
【输入】
  输入文件名为 war.in。
  第一行一个正整数 N,代表城池的个数。
  接下来 N 行,每行一个正整数,代表这个城市的强大值。
【输出】
  输出文件名为 war.out。
  一行一个整数,代表最大的安全值。
【输入输出样例】
  War.in
  4
  1
  2
  3
  4
  War.out
  4
【数据范围】
  对于 30%的数据,保证有 n≤1000。
  对于 100%的数据,保证有 n≤1000000, 任意 W 小于等于 1000000。

【Analysis】

  对于任意质数,设起在A中次数为a,在A1中次数为a1,在B中次数为b,在B1中次数为b1,在X中次数为x,则min(a,a1)=x,max(b,b1)=x;据此求x的取值范围

【code】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int A = 1e6;
 7 
 8 int n,maxn,pre,k,x,y,q,s,z;
 9 int w[A+10],vis[A+10][2],f[A+10];
10 long long ans;
11 
12 int find(int x)
13 {
14     if(x!=f[x])f[x]=find(f[x]);
15     return f[x];
16 }
17 
18 int main()
19 {
20     freopen("war.in","r",stdin);
21     freopen("war.out","w",stdout);
22     scanf("%d",&n);
23     for(int i=1;i<=n;++i)f[i]=i;
24     for(int i=1;i<=n;++i)
25     {
26         scanf("%d",&w[i]);
27         if(w[i]>maxn)maxn=w[i];
28         if(!vis[w[i]][0]){vis[w[i]][0]=1;vis[w[i]][1]=i;}
29         else {ans+=w[i];f[vis[w[i]][1]]=i;++s;}//
30     }
31     
32     for(int i=maxn;i>=1;--i)//
33     {
34         pre=0;
35         for(int j=1;i*j<=maxn;++j)
36         {
37             k=i*j;
38             if(vis[k][0])
39             {
40                 if(!pre)pre=vis[k][1],q=k;
41                 else
42                 {
43                     x=find(pre);y=find(vis[k][1]);
44                     if(x!=y)
45                     {
46                         ans+=i;f[x]=y;++s;
47                     }
48                 }
49             }
50         }
51         if(s==n-1)break;
52     }
53     printf("%lld\n",ans);
54     return 0;
55 }

 

【小 Y 的数学作业】(Homework.pas/c/cpp Time:1s Memory:256M)
【问题描述】
小 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。
【输入输出样例】
  Homework.in
  2
  41 1 96 288
  95 1 37 1776
  Homework.out
  6
  2
【数据范围】
  对于 50%的数据,保证有 1≤A,A1,B,B1≤10000 且 n≤100。
  对于 100%的数据,保证有 1≤A,A1,B,B1≤2,000,000,000 且 n≤2000。

【Analysis】
  从大到小枚举边权,vis[i][0]记存在权值为i的点,vis[i][1]记初始父亲,要处理点权相同的情况
【code】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int size = 45000;
 7 
 8 int A,A1,B,B1,a,a1,b,b1,x,s,sum,l,r,T,bo,bb;
 9 int p[size+10],ex[size+10];
10 long long ans=1;
11 
12 void prime()
13 {
14     for(int i=2;i<=size;++i)
15     {
16         if(!ex[i])p[++s]=i;
17         for(int j=1;j<=s&&p[j]*i<=size;++j)
18         {
19             ex[p[j]*i]=1;
20             if(i%p[j]==0)break;
21         }
22     }
23 }
24 
25 int solve(int &a,int b)
26 {
27     sum=0;
28     while(a%b==0)++sum,a/=b;
29     return sum;    
30 }
31 
32 int main()
33 {    
34     freopen("homework.in","r",stdin);
35     freopen("homework.out","w",stdout);
36     prime();
37     scanf("%d",&T);
38     while(T--)
39     {
40         ans=1;bo=0;
41         scanf("%d%d%d%d",&A,&A1,&B,&B1);
42         if(B1%A1){printf("0\n");continue;}
43         bb=B1;
44         for(int i=1;i<=s;++i)
45         {
46             if(p[i]>bb) break;
47             x=-1;l=-1;r=-1;//
48             a=solve(A,p[i]);
49             a1=solve(A1,p[i]);
50             b=solve(B,p[i]);
51             b1=solve(B1,p[i]);
52             if(a==a1)l=a;
53             else x=a1;
54             if(b==b1)r=b;
55             else
56             {
57                 if(x>=0&&b1!=x){bo=1;break;}
58                 x=b1;
59             }
60             if(l>r&&l>=0&&r>=0){bo=1;break;}
61             if(x<0)ans*=(r-l+1);
62         }
63         if(A>1&&A1>1)ans*=2;
64         if(B>1&&B1>1)ans*=2;
65         if(bo)printf("0\n");
66         else printf("%lld\n",ans);
67     }
68     return 0;
69 }

 

posted @ 2017-04-08 17:35  Etta19  阅读(218)  评论(0编辑  收藏  举报