CodeVS第四次月赛解题报告

1.   奶牛的身高

题目描述 Description

奶牛们在FJ的养育下茁壮成长。这天,FJ给了奶牛Bessie一个任务,去看看每个奶牛场中若干只奶牛的身高,由于Bessie是只奶牛,无法直接看出第i只奶牛的身高,而只能看出第i只奶牛与第j只奶牛的身高差,其中第i只奶牛与第j只奶牛的身高差为Ai(i<=n)。当A大于0时表示这只奶牛比前一只奶牛高A cm,小于0时则是低。现在,FJ让Bessie总共去看了m次身高,当然也就传回给FJ m对奶牛的身高差,但是Bessie毕竟是奶牛,有时候眼睛可能会不好使……(大雾)你的任务是帮助FJ来判断是不是需要给Bessie看看眼睛了……

注:Hj-Hi=A 注意T1的样例 注意注意注意 重要的事情说三遍。

 

输入描述 Input Description

第一行为一个正整数w,表示有w组数据,即w个奶牛场,需要你判断。每组数据的第一行为两个正整数n和m,分别表示对应的奶牛场中的奶牛只数以及看了多少个对奶牛身高差。接下来的m行表示Bessie看m次后传回给FJ的m条信息,每条信息占一行,有三个整数s,t和v,表示第s只奶牛与第t只奶牛的身高差为v。

 

输出描述 Output Description

包含w行,每行是”Bessie’s eyes are good”或”Bessie is blind.”(不含双引号),其中第i行为”Bessie’s eyes are good”当且仅当第i组数据,即无法从第i个奶牛场传回的身高差判断Bessie视力好不好;第i行为”Bessie is blind.”当且仅当第i组数据,即从第i个奶牛场传回的身高差是有问题的。

 

样例输入 Sample Input

2

3 3

1 3 10

2 3 5

1 2 5

4 3

1 4 100

3 4 50

1 3 100

 

样例输出 Sample Output

Bessie’s eyes are good

Bessie is blind.

 

数据范围及提示 Data Size & Hint

对于30%的数据,保证n<=100,m<=1000;

对于100%的数据,保证w<=100,n<=1000,m<=30000,|A|<=30000.

 

解题报告 Solution

可以说是比较经典的边带权并查集题目。

如果这道题限制|A|>0就可以用拓扑排序做了,然而既然没有限制,就要转变思路。

设g[x]代表fa[x]与x的身高差(即H[fa[x]]-H[x]),对于一条信息(u, v, w),若u和v不在一个集合,则将两个集合合并,更新g。如果不在一个集合的话,判定是否与以前的冲突(冲突可以理解为有(H[a]-H[k])+(H[k]-H[b])≠H[a]-H[b]),那么就是无解。

更新g和上面的判断都用到了方程做和,具体请看代码。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<queue>
 6 #include<algorithm>
 7 using namespace std;
 8 
 9 //variable//
10 int n,m,fa[10010],g[10010];
11 
12 //function prototype//
13 int getfa(int);
14 
15 //solve//
16 int main(){
17     int t;
18     scanf("%d",&t);
19     while (t--){
20         scanf("%d%d",&n,&m);
21         for (int i=1;i<=n;++i) fa[i]=i,g[i]=0;
22         bool flag=true;
23         while (m--){
24             int u,v,w;
25             scanf("%d%d%d",&u,&v,&w);
26             int fu=getfa(u),fv=getfa(v);
27             if (fu!=fv){
28                 fa[fu]=fv;
29                 g[fu]=g[v]-g[u]+w;
30             }else{
31                 if (w!=g[u]-g[v]){
32                     if (flag) puts("Bessie is blind.");
33                     flag=false;
34                 }
35             }
36         }
37         if (flag) puts("Bessie's eyes are good");
38     }
39     return 0;
40 }
41 
42 int getfa(int x){
43     if (fa[x]==x) return x;
44     int f=fa[x];
45     fa[x]=getfa(fa[x]);
46     g[x]+=g[f];
47     return fa[x];
48 }
View Code

2.   奇特的生物

题目描述 Description

科学家们最近发现了一种奇怪的生物,它们每天长大一岁,刚出生的宝宝为1岁,且它们的年龄没有上限。已知年龄为1岁,2岁,3岁,……,k岁的个体具有生育能力,当年龄为i的具有生育能力的个体将长大一岁时会生下ai个1岁的幼崽。假设第一天只有一个年龄为1的幼崽,现在科学家们想知道第x天年龄为y的个体有多少,但由于该物种增长速度太快,于是他们将这个任务交给了你。由于这个数可能很大,你需要对p取模。

 

输入描述 Input Description

输入数据第一行给定四个整数k,x,y,p。

第二行包括k个整数,第i个整数代表ai。

 

输出描述 Output Description

输出数据包含一行,表示第x天年龄为y的个体的数量对p取模后的结果。

 

样例输入 Sample Input

【样例输入 1】

3 3 1 1007

1 1 1

【样例输入 2】

3 6 2 1007

1 2 1

 

样例输出 Sample Output

【样例输出1】

2

【样例输出 2】

13

 

数据范围及提示 Data Size & Hint

0<=x<=1014, 0<=y<=1014, 1<=p<=1012, 1<=k<=10, 1<=ai<=100

 

解题报告 Solution

一次递推式快速幂矩阵乘法。

因为最大数据的p<=1012,所以涉及乘法的地方把一个大数拆分。

自己看码吧。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 //variable//
 9 typedef unsigned long long ull;
10 int k;
11 ull a[10]={0},f[10][10],x,y,p;
12 
13 //function prototype//
14 ull dminus(ull,ull);
15 
16 //solve//
17 int main(){
18     scanf("%d%lld%lld%lld",&k,&x,&y,&p);
19     for (int i=0;i<k;++i) scanf("%lld",f[i]);
20     if (x<y){
21         puts("0");
22         return 0;
23     }
24     a[0]=1;
25     for (int i=1;i<k;++i) f[i-1][i]=1;
26     x-=y;
27     while (x){
28         if (x&1){
29             ull b[10]={0};
30             for (int i=0;i<k;++i)
31                 for (int j=0;j<k;++j)
32                     b[j]=(b[j]+dminus(a[i],f[i][j]))%p;
33             memcpy(a,b,sizeof b);
34         }
35         x>>=1;
36         ull b[10][10]={0};
37         for (int i=0;i<k;++i)
38             for (int j=0;j<k;++j)
39                 for (int l=0;l<k;++l)
40                     b[i][j]=(b[i][j]+dminus(f[i][l],f[l][j]))%p;
41         memcpy(f,b,sizeof b);
42     }
43     cout<<a[0]<<endl;
44 }
45 
46 ull dminus(ull a,ull b){
47     ull x=a/1000000,y=a%1000000;
48     return ((x*b)%p*(1000000llu%p)+(y*b)%p)%p;
49 }
View Code
  1. 1.   NTT

题目描述 Description

经历过大战之后的 tty,传说中的 Long'Aotian 职阶的骑士,开始研究数学。

他定义数列 fi ,这个数列的第 i 项,即 fi 表示不大于 i 且与 i 的互质的数的个数。例如 f1 = 1 , f3 = 2 , f6 = 2 , f18 = 6

他还定义了一种奇特的数学关系:对于正整数 m, n,如果 2m -1 | 2n - 1,并且 m 能被至少一个大于 1 完全平方数整除,就称 m 是 n 的“可协调数”。

现在对于给定的 n,他希望你求出 sum (fm) (m 是 n 的“可协调数”)。

注意有多组数据。sum (fm)为fm的和

 

输入描述 Input Description

第 1 行,一个正整数 T 表示数据组数。

接下来 T 行,每行一组数据,只包含一个正整数 n.

 

输出描述 Output Description

输出文件应包含 T行。

对于每组数据,输出 1行,表示你的答案。

 

样例输入 Sample Input

3

7

8

9

 

样例输出 Sample Output

0

6

6

 

数据范围及提示 Data Size & Hint

【样例解释】

7没有“可协调数”,答案为0。

8可协调数为4、8,而f4=2,f8=4,答案为f4+f8=6

9的可协调数为9,f9=6,答案为6。

【数据范围】

T=5,n<=1018

 

解题报告 Solution

首先fi其实就是欧拉函数。2m -1 | 2n - 1⇔ m|n。

有一个重要性质:∑d|nφ(d)=n。但是这并不是答案,因为一些非平方数约数的d被计算了进来。所以我们要减去它们的phi。

对于一个不能被任意平方数整除的d,它一定可以被唯一表示为p1*p2*…*pn(p1≠p2≠…≠pn),所以依照phi的求值公式,phi(d)= (p1-1)*(p2-1)*…*(pn-1)(p1≠p2≠…≠pn)。又d是n的约数,所以{pn}都是n的质因子。将所有的不能被平方数整除的且是n的约数的d的phi写在一起,经过合并,发现他们的和就是所有n质因子的积。

 1 #include <cstdio>
 2 #include <cmath>
 3 using namespace std;
 4 
 5 unsigned long long t,n;
 6 
 7 int main(){
 8     for (scanf("%llu",&t);t--;){
 9         scanf("%llu",&n);
10         unsigned long long s=1,m=n;
11         for (unsigned long long i=2;i*i*i<=m;i++){
12             if (m%i==0){
13                 while (m%i==0) m/=i;
14                 s*=i;
15             }
16         }
17         if (m>1){
18             if (floor(sqrt(m))==sqrt(m)) s*=floor(sqrt(m));
19             else s*=m;
20         }
21         printf("%llu\n",n-s);
22     }
23     return 0;
24 }
View Code

 

posted @ 2015-10-08 07:48  DeAR3327  阅读(141)  评论(0编辑  收藏  举报