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 }
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 }
- 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 }