nowcoder 185 牛客OI赛制测试赛2

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 }
A. 无序组数

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 }
B. 路径数量

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 }
C. 数列下标

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 }
D. 星光晚餐

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 }
E. 括号序列

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 }
F. 假的数学游戏

转载于:https://www.cnblogs.com/KingSann/articles/9602702.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值