A. 无序组数
题目描述:
给出一个二元组(A,B)
求出无序二元组(a,b) 使得(a|A,b|B)的组数
无序意思就是(a,b)和(b,a) 算一组
输入描述:
第一行数据组数 T(1≤T≤10000)
接下来T行,每行两个正整数 A,B(1≤A,B≤10000)
输出描述:
共T行,每行一个结果
如果要求统计有序的话,答案显然是$\sigma_0(A)\sigma_0(B)$
要求无序的话,也就是额外要求统计有多少个$x \not= y$,且$x \mid A, y \mid A, x \mid B, y \mid B$,既$x \mid \gcd(A,B), y \mid \gcd(A, B)$
也就是${\sigma_0(\gcd(A,B)) \choose 2}$
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 10000 + 10; 5 ll x[N]; 6 7 int gcd(int a, int b) { 8 return b ? gcd(b, a % b) : a; 9 } 10 11 void sol() { 12 int a, b; 13 scanf("%d%d", &a, &b); 14 ll cd = x[gcd(a, b)]; 15 ll t = cd * (cd - 1) / 2; 16 printf("%lld\n", x[a] * x[b] - t); 17 } 18 19 int main() { 20 for(int i = 1 ; i <= 10000 ; ++ i) { 21 for(int j = i ; j <= 10000 ; j += i) { 22 ++ x[j]; 23 } 24 } 25 int T; scanf("%d", &T); 26 while(T --) sol(); 27 }
B. 路径数量
题目描述
给出一个 n * n 的邻接矩阵A.
A是一个01矩阵.
A[i][j]=1表示i号点和j号点之间有长度为1的边直接相连.
求出从 1 号点 到 n 号点长度为k的路径的数目.
输入描述
第1行两个数n,k (20 ≤n ≤ 30,1 ≤ k ≤ 10)
第2行至第n+1行,为一个邻接矩阵
输出描述
题目中所求的数目
答案显然是邻接矩阵的$k$次方的$(1,n)$项
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 int n, k; 6 7 struct Mat { 8 ll a[30][30]; 9 ll* operator [] (int x) { return a[x]; } 10 Mat() { memset(a, 0, sizeof a); } 11 } a; 12 13 Mat operator * (Mat a, Mat b) { 14 Mat c; 15 for(int i = 0 ; i < n ; ++ i) 16 for(int j = 0 ; j < n ; ++ j) 17 for(int k = 0 ; k < n ; ++ k) 18 c[i][j] += a[i][k] * b[k][j]; 19 return c; 20 } 21 22 int main() { 23 scanf("%d%d", &n, &k); 24 for(int i = 0 ; i < n ; ++ i) 25 for(int j = 0 ; j < n ; ++ j) 26 scanf("%lld", &a[i][j]); 27 Mat res; 28 for(int i = 0 ; i < n ; ++ i) res[i][i] = 1; 29 for(int i = 1 ; i <= k ; ++ i) res = res * a; 30 printf("%lld\n", res[0][n - 1]); 31 }
C. 数列下标
题目描述
给出一个数列 A,求出一个数列B.
其中Bi表示数列A中 Ai 右边第一个比 Ai 大的数的下标(从1开始计数),没有找到这一个下标Bi就为0
输出数列B
输入描述
第一行1个数字 n (n ≤ 10000)
第二行n个数字第 i 个数字为 Ai (0 ≤ Ai ≤ 1000000000)
输出描述
一共一行,第 i 个数和第 i+1 个数中间用空格隔开.
直接暴力即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e4 + 10; 5 int a[N], b[N], n; 6 struct FastIO { 7 static const int S = 1e7; 8 int wpos; 9 char wbuf[S]; 10 FastIO() : wpos(0) {} 11 inline int xchar() { 12 static char buf[S]; 13 static int len = 0, pos = 0; 14 if (pos == len) 15 pos = 0, len = fread(buf, 1, S, stdin); 16 if (pos == len) exit(0); 17 return buf[pos++]; 18 } 19 inline int xuint() { 20 int c = xchar(), x = 0; 21 while (c <= 32) c = xchar(); 22 for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; 23 return x; 24 } 25 ~FastIO() 26 { 27 if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; 28 } 29 } io; 30 int main() { 31 // freopen("data.in", "r", stdin); 32 // freopen("data.out", "w", stdout); 33 n = io.xuint(); 34 for(int i = 1 ; i <= n ; ++ i) a[i] = io.xuint(); 35 for(int i = 1 ; i <= n ; ++ i) { 36 for(int j = i + 1 ; j <= n ; ++ j) { 37 if(a[i] < a[j]) { 38 b[i] = j; 39 break; 40 } 41 } 42 // cout << "i = " << i << endl; 43 } 44 for(int i = 1 ; i <= n ; ++ i) printf("%d ", b[i]); 45 }
D. 星光晚餐
题目描述
Johnson和Nancy要在星光下吃晚餐。
这是一件很浪漫的事情。
为了增加星光晚餐那浪漫的氛围,他拿出了一个神奇的魔法棒,并且可以按照一定的规则,改变天上星星的亮暗。
Johnson想考考Nancy,在他挥动魔法棒后,会有多少颗星星依旧闪耀在天空。
他知道,Nancy一定会一口说出答案。
Nancy当然知道怎么做啦,但她想考考你!
Johnson先将天上n个星星排成一排,起初它们都是暗的。
他告诉他的妹子,他将挥动n次魔法棒,第i次挥动会将编号为i的正整数倍的星星的亮暗反转,即亮的星星转暗,暗的星星转亮。
Johnson想问Nancy,最终会有多少个星星依旧闪亮在天空。
输入描述
一个整数n,含义请见题目描述。
输出描述
一个整数ans,即n次操作后会有多少个星星依旧闪亮。
显然是让求$\sum_{i=1}^{n} \sigma_0(i) \bmod 2$
显然只有完全平方数才会对答案产生贡献,也就是说输出$\lfloor \sqrt n \rfloor$
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll n; 6 7 ll calc(ll n) { 8 if(n <= 0) return 0; 9 ll l = 1, r = 1e9, ans = 0; 10 while(l <= r) { 11 ll mid = (l + r) >> 1; 12 if(mid * mid <= n) { 13 ans = mid; 14 l = mid + 1; 15 } else { 16 r = mid - 1; 17 } 18 } 19 return ans; 20 } 21 22 int main() { 23 ll n; scanf("%lld", &n); 24 printf("%lld\n", calc(n)); 25 }
E. 括号序列
题目描述
给定括号长度N,给出一串括号(只包含小括号),计算出最少的交换(两两交换)次数,使整个括号序列匹配。
我们认为一个括号匹配,即对任意一个')',在其左侧都有一个'('与它匹配,且他们形成一一映射关系。
输入描述
第一行:整数N,表示括号序列长度
第二行:一个字符串,表示括号
输出描述
一个整数,表示最少的交换次数
已经匹配的括号不需要再移动,那么就先把所有匹配的括号都删掉,剩下一定是$)))))((((($的形式
假设一共有$cnt$个$)$,那么答案就是$\lceil \frac{cnt}{2} \rceil$
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 5e6 + 10; 5 char s[N]; 6 int n; 7 8 int main() { 9 scanf("%d%s", &n, s + 1); 10 int cnt = 0, tot = 0; 11 for(int i = 1 ; i <= n ; ++ i) { 12 if(s[i] == '(') ++ tot; 13 else { 14 if(tot) -- tot; 15 else ++ cnt; 16 } 17 } 18 n = cnt; 19 printf("%d\n", n / 2 + (n % 2 != 0)); 20 }
F. 假的数学游戏
题目描述
输入一个整数X,求一个整数N,使得N!恰好大于X。
输入描述
第一行:一个整数X
输出描述
第一行:一个整数N
备注
每个测试点所对应的X满足:
第i个测试点输入的值为第i-1个测试点输入的值乘以10再加上7。
特别的,第一个测试点所输入的值为7。
提示:数据共有10组。
一个比较暴力的方法:
$$\begin{align} n! &\gt x^x \\ \log_x n! &\gt x \\ \frac{1}{\lg x}\sum_{i=1}^{n}\lg i & \gt x \end{align}$$
暴力枚举$n$即可
当然有一种十分简单的做法了……百度:斯特林公式
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll n; 5 int main() { 6 // freopen("data.in", "r", stdin); 7 cin >> n; 8 if(n == 7) puts("10"); 9 if(n == 77) puts("94"); 10 if(n == 777) puts("892"); 11 if(n == 7777) puts("8640"); 12 13 // ??? 14 if(n == 77777) puts("84657"); 15 if(n == 777777) puts("834966"); 16 if(n == 7777777) puts("8267019"); 17 if(n == 77777777) puts("82052137"); 18 if(n == 777777777) puts("815725636"); 19 if(n == 7777777777) puts("8118965902"); 20 }