比赛链接https://ac.nowcoder.com/acm/contest/89860
A - TD 题意 有m个人,其中n个人发送了TD,那么从m个人中随机挑选一个人,他发送过TD的概率是多少。
思路 直接输出undefinedfrac{n}{m}$ 即可(要注意这里不是整数除法)
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int n,m;cin>>n>>m; cout<<double (n)/m<<endl; } signed main () { int T = 1 ; while (T--){ solve (); } return 0 ; }
B - 你好,这里是牛客竞赛 题意 给你一个链接,如果这个链接以https://ac.nowcoder.com或者ac.nowcoder.com 开头,就输出Ac
如果链接以https://www.nowcoder.com 或者www.nowcoder.com 开头,就输出Nowcoder ,
如果都不是,那么就输出No
思路 可以先判断前几个字符如果是https;//就删掉这部分。
然后我们读取字符串,直到遇到.com就停止。
最后对读取的字符串判断即可。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { string str; cin>>str; if (str.substr (0 ,8 ) == "https://" ){ str = str.substr (8 ); } string ans = "" ; for (int i = 0 ;i<str.size ();i++){ if (i >= 3 && str.substr (i-3 ,3 ) == "com" ) break ; ans += str[i]; } if (ans == "ac.nowcoder.com" ) cout<<"Ac\n" ; else if (ans == "www.nowcoder.com" ) cout<<"Nowcoder\n" ; else cout<<"No\n" ; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }
C - 逆序数 题意 已知一个**排列**undefined{ x_1 ,x_2,…,x_n \}k\{x_n,…,x_2,x_1\}$ 的逆序对数量。
现在给你 ,请你输出结果。
思路 一个长度为n的排列,一共有undefinedfrac{n*(n-1)}{2}t,kans = t = \frac{n*(n-1)}{2} - k$
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int n,k; cin>>n>>k; cout<<n*(n-1 )/2 - k; } signed main () { int T = 1 ; while (T--){ solve (); } return 0 ; }
D - 构造mex 题意 给你整数,请你将分为**恰好**n个非负整数, 使得 并且 。
注:的含义是**在a数组中,未出现过的最小的非负整数**。
思路 大讨论题,对于一般情况,我们很容易得知,需要构造 这样的数列。但是本题的关键在于考虑特殊情况。下面列举需要特判的条件:
如果 并且 ,条件无法成立那(这n个数中一定存在0,就不能使得k = 0.)
如果 ,那么无论如何都不能成立。(a数组一定为一个1和一些0(可能为0个0),最后的mex一定为0或2,不是1)
如果 那么无法成立(显然无法分出k份也就无法使得都在中出现,也就无法使得最终的mex是k)
如果 且 ,无法成立(如果n和k相等,就代表应该恰好将s分为 这k个数,如果总和不是s就违背了构造规则)
如果 并且 那么无法成立(即我们需要设置a数组为 , 那么它的mex就变为了 而不是)
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int s,n,k; cin>>s>>n>>k; int sum = k*(k-1 )/2 ; if (k == 0 ){ if (s < n) {cout<<"NO\n" ;return ;} cout<<"YES\n" ; rep (i,1 ,n-1 ){ cout<<1 <<' ' ; }cout<<s-n+1 ; puts ("" );return ; } if (k == 1 && s == 1 ){cout<<"NO\n" ;return ;} if (n < k) {cout<<"NO\n" ; return ;} if (sum > s) {cout<<"NO\n" ; return ;} if (n == k) { if (sum != s) {cout<<"NO\n" ; return ;} else { cout<<"YES\n" ; rep (i,0 ,n-1 ){ cout<<i<<' ' ; }puts ("" );return ; } } if (n == (k+1 ) && sum+k == s) {cout<<"NO\n" ;return ;} cout<<"YES\n" ; for (int i = 0 ;i<k;i++){ cout<<i<<' ' ; } int left = s-sum; if (left == k){ cout<<1 <<" " <<k-1 <<' ' ; for (int i = k+3 ;i<=n;i++) cout<<"0 " ; }else { cout<<left<<' ' ; for (int i =k+2 ;i<=n;i++) cout<<"0 " ; } puts ("" );return ; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }
E - 小红的X型矩阵 题意 给你一个 的01矩阵, 你进行若干次如下操作,使得最终的矩阵为X型矩阵 ,操作方法如下:
操作一:将矩阵中的一个元素反转(0变为1,1变为0)
操作二:将矩阵循环右移或者循环下移一位。
问最少需要几次操作一,能够使得矩阵变为X型矩阵
注:当且仅当一个矩阵的两个对角线全为1,其余地方全为0时,该矩阵为X型矩阵 ( 其余全为0)
思路 我们将最终目标的X矩阵进行一些次数的循环移动后,可以发现,X的中心移动到了矩阵中的某个位置,而其他的1同样在它的四个角落方向(若越界则循环至矩阵另一边),因此这些1同样在两条对角线上。
1 2 3 4 5 10001 11000 01010 11000 00100 ---> 00101 01010 00010 10001 00101
因此我们对输入矩阵维护每条对角线上的1的数量,然后我们枚举中心点的每个位置,找到和原矩阵匹配程度最大的那个即可(即在这两条对角线上,原矩阵的1出现的数量最多)。
需要注意如果n为偶数,因为两条对角线不存在交点,那么处理方式和奇数略有不同。
可以发现对于左上-右下对角线,我们可以这样表示它: (对于每个,表示一条对角线)
对于左下-右上对角线,可以这样表示它:(对于每个,表示一条对角线)
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;int mp[1005 ][1005 ];int n;int sum1[2005 ];int sum2[2005 ];void solve () { cin>>n; int sum = 0 ; for (int i =1 ;i<=n;i++){ for (int j = 1 ;j<=n;j++){ cin>>mp[i][j]; if (mp[i][j]) sum ++ ; } } for (int d = 0 ;d<=n-1 ;d++){ for (int i = 1 ;i<=n;i++){ int j = i + d; if (j > n) j -=n; sum1[d] += mp[i][j]; } } for (int d = 0 ;d<=n-1 ;d++){ for (int i = 1 ;i<=n;i++){ int j = d - i; if (j < 1 ) j += n; sum2[d] += mp[i][j]; } } int res = INF; if (n%2 == 1 ){ for (int i = 1 ;i<=n;i++){ for (int j =1 ;j<=n;j++){ int cnt = sum1[(j-i+n)%n] + sum2[(i+j)%n] - mp[i][j]; int ans =(2 * n - 1 - cnt) + (sum - cnt); res = min (res,ans); } } }else { for (int i = 1 ;i<=n;i++){ for (int j = 1 ;j<=n;j++){ int cnt = 0 ; cnt += sum1[(j-i+n)%n]; int ii = i%n+1 ; cnt += sum2[(ii+j)%n]; int ans =(2 * n - cnt) + (sum - cnt); res = min (res,ans); } } } cout<<res; } signed main () { int T = 1 ; while (T--){ solve (); } return 0 ; }
F - 小红的数组回文值 题意 定义一个数组的回文值为:至少需要修改多少个数,能使得这个数组变为回文数组。
现在给你一个长度为的数组 ,问它的所有**子序列**的回文值的和是多少。答案对 取模
思路 我们应该先想到,一个数组的回文值,即为每对**对称的数** 不相等的数量。例: ,那么undefined1,7)(2,5)$ 对称,并且这两个对都不相同,回文值为2。
即**只有不相同的数对会产生贡献**。 那么我们枚举数组a中的每个数对undefineda_i, a_j )$, 如果他们不相等, 我们就计算在多少个子序列中,这两个数是对称的。
很容易求出对于给定的undefinedi,j)mid = j-i-1le = i-1ri = n-j$ 个数。
分布如下:...i.....j....
我们得知,选择中间的任意数不会破坏和对称。那么他们有 种方案。
对于两侧,我们必须选择同样多的数,才能保证和是对称的。假设我们选择了个数。
于是两侧的方案数为undefinedsum_{k=0}^{min(le,ri)} C_{le}^{k} C{ri}^kC_n^m = C_n^{n-m}\sum_{k=0}^{min(le,ri)} C_{le}^{le-k} C_{ri}^kC_{le+ri}^{le}(i,j)2^{mid} * C_{le+ri}^{le}$
注:范德蒙恒等式如下: , 解释为:有两个盒子,分别装有个球和个球 , 从中一共选择k个球() 等价于, 从第一个盒子中选择t个球,从另一个盒子中选择个球 。枚举每个 将方案数相加。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;int a[2005 ];int fac[2005 ];int ifac[2005 ];const int mod = 1e9 +7 ;int qpow (int x,int n) { int ans = 1 ; while (n){ if (n&1 ) ans = ans * x % mod; x = x * x % mod; n >>= 1 ; } return ans; } int inv (int x) { return qpow (x,mod-2 ); } int C (int n,int m) { if (m == 0 || n == m) return 1 ; return fac[n] * ifac[n-m] % mod * ifac[m] % mod; } void solve () { fac[0 ] = 1 ; for (int i = 1 ;i<=2000 ;i++) fac[i] = fac[i-1 ] * i % mod; for (int i = 1 ;i<=2000 ;i++) ifac[i] = inv (fac[i]); int n; cin>>n; for (int i = 1 ;i<=n;i++){ cin>>a[i]; } int ans = 0 ; for (int i = 1 ;i<=n;i++){ for (int j = i+1 ;j<=n;j++){ int l = i-1 ,m = (j-i-1 ),r=(n-j); int sum = 0 ; int mn = min (l,r); ans = (ans + (a[i]!=a[j])*qpow (2 ,m)*(C (l+r,l))%mod)%mod; } } cout<<ans; } signed main () { int T = 1 ; while (T--){ solve (); } return 0 ; }