CF845 A - B

文章介绍了两道编程竞赛题目,一道涉及数组的好坏定义及其最少操作次数,另一道关注数组的全排列及逆序对数量。对于第一题,关键在于找到将相邻相同奇偶性的元素合并的策略;第二题则需要计算所有排列的逆序对总数,发现并利用其中的规律。
摘要由CSDN通过智能技术生成

前言

人生中第一场cf,由于本人太菜了,所以才涨了436分,但是我很好奇,为什么相差三千多名,只值46分。

题面

A - Everybody Likes Good Arrays!

An array a a a is good if for all pairs of adjacent elements, a i a_i ai and a i + 1 ( 1 ≤ 𝑖 < n ) a_i+1 (1 \le 𝑖 < n) ai+1(1i<n) are of different parity. Note that an array of size 1 is trivially good.
You are given an array of size n n n.
In one operation you can select any pair of adjacent elements in which both elements are of the same parity, delete them, and insert their product in the same position.
Find the minimum number of operations to form a good array.

Input

Each test contains multiple test cases. The first line contains the number of test cases t ( 1 ≤ 𝑡 ≤ 500 ) t (1 \le 𝑡 \le 500) t(1t500). The description of the test cases follows.

The first line of each test case contains an integer n ( 1 ≤ n ≤ 100 ) n (1 \le n \le 100) n(1n100)

The second line of each test case contains n n n integers a 1 , a 2 , … , a n ( 1 ≤ a i ≤ 1 0 9 ) a_1,a_2,\dots,a_n (1 \le a_i \le 10^9) a1,a2,,an(1ai109)

Output

For each test case print an integer, the minimum number of operations required to form a good array.

Example

input
3
5
1 7 11 2 13
4
1 2 3 4
6
1 1 1 2 2 3
output
2
0
3

Note

Consider the first test case. Select the 2
-nd and the 3
-rd integers and apply the operation on them. The array changes from [ 1 , 7 , 11 , 2 , 13 ] [1,7,11,2,13] [1,7,11,2,13] to [ 1 , 77 , 2 , 13 ] [1,77,2,13] [1,77,2,13]
. Next, select the 1-st and the 2-nd integers, array changes from [ 1 , 77 , 2 , 13 ] [1,77,2,13] [1,77,2,13] to [ 77 , 2 , 13 ] [77,2,13] [77,2,13]
. Thus we require 2 operations. It can be proved that this is the minimum number of operations.
In the second test case, the given array is already good. So we require 0 operations.

B - Emordnilap

A permutation of length n n n is an array consisting of n n n distinct integers from 1 to n n n in arbitrary order. For example, [ 2 , 3 , 1 , 5 , 4 ] [2,3,1,5,4] [2,3,1,5,4] is a permutation, but [ 1 , 2 , 2 ] [1,2,2] [1,2,2] is not a permutation (2 appears twice in the array), and [ 1 , 3 , 4 ] [1,3,4] [1,3,4] is also not a permutation ( n n n=3 but there is 4 in the array). There are n ! = n × ( n − 1 ) × ( n − 2 ) × ⋯ × 1 n! = n \times (n - 1) \times (n - 2) \times \dots \times 1 n!=n×(n1)×(n2)××1 different permutations of length n n n.

Input

Each test contains multiple test cases. The first line contains the number of test cases t ( 1 ≤ t ≤ 1 0 5 ) t (1 \le t \le 10^5) t(1t105). The description of the test cases follows.

Each test case has only one line — the integer n ( 1 ≤ n ≤ 1 0 5 ) n (1 \le n \le 10^5) n(1n105)
It is guaranteed that the sum of n n n over all test cases does not exceed 1 0 5 10^5 105.

Output

For each test case, print one integer — the sum of beauties of all permutations of size n n n modulo 1000000007 ( 1 0 9 + 7 ) (10^9+7) (109+7).

Example

input
3
1
2
100
output
0
4
389456655

Note

For the first test case of the example, p = [ 1 ] [1] [1] is the only permutation. a a a = [ 1 , 1 ] [1,1] [1,1] has 0 inversions.
For the second test case of the example, the permutations are [ 1 , 2 ] [1,2] [1,2] and [2,1]
. Their respective a a a arrays are [ 1 , 2 , 2 , 1 ] [1,2,2,1] [1,2,2,1] and [ 2 , 1 , 1 , 2 ] [2,1,1,2] [2,1,1,2], both of which have 2 inversions.

题面翻译

(提示:这只是翻译而已,没有思路题解成分。)

A - Everybody Likes Good Arrays!

我们定义一个好的数组,当且仅当数组中的每一个变量都与左边或右边的数除以2
的余数不同。
[ 1 , 2 , 3 ] [1,2,3] [1,2,3]是,而 [ 1 , 2 , 2 ] [1,2,2] [1,2,2]不是,因为第二个数组中, a 2 除以 2 的余数是 0 ,而 a 3 除以 2 的余数也是 0 ,所以 [ 1 , 2 , 2 ] 不是好的数组 a_2除以2的余数是0 ,而a_3 除以 2的余数也是0,所以[1,2,2]不是好的数组 a2除以2的余数是0,而a3除以2的余数也是0,所以[1,2,2]不是好的数组
我们可以选择一个数组中的任意两个相邻的数,删除他们,然后再将它们的乘积放入里面,问你,至少要多少次操作才能使得原数组是一个好的数组。

对于样例一, [ 1 , 7 , 11 , 2 , 13 ] [1,7,11,2,13] [1,7,11,2,13],我们先合并 [ 7 , 11 ] [7,11] [7,11],变成 [ 1 , 77 , 2 , 13 ] [1,77,2,13] [1,77,2,13],然后再合并 [ 1 , 77 ] [1,77] [1,77],变成 [ 77 , 2 , 13 ] [77,2,13] [77,2,13],所以只需要两次。

B - Emordnilap

求出 n n n的所有排列复制后反向插入数组后,修改后的数组的逆序对个数的总和。
如:2 , 他的全排列分别为: [ 1 , 2 ] , [ 2 , 1 ] [1,2] , [2,1] [1,2],[2,1]
修改后分别变为: [ 1 , 2 , 2 , 1 ] 和 [ 2 , 1 , 1 , 2 ] [1,2,2,1]和[2,1,1,2] [1,2,2,1][2,1,1,2],他们都有2个逆序对。
所以答案为2+2=4

题解

A - Everybody Likes Good Arrays!

思路

这道题的提示有点误导性。
这道题其实很简单,我们只需要一个数组分成若干块,分的规则是相邻的奇数或偶数一块。如: [ 1 , 10 , 6 , 23 , 15 , 17 , 8 ] [1,10,6,23,15,17,8] [1,10,6,23,15,17,8],把它分成 [ 1 ] , [ 10 , 6 ] , [ 23 , 15 , 17 ] , [ 8 ] [1],[10,6],[23,15,17],[8] [1],[10,6],[23,15,17],[8]
因为相邻的,奇偶性相同必须乘起来,(奇数 $\times $ 奇数 = 奇数 , 偶数 $\times $ 偶数 = 偶数,奇偶性相同的乘起来,奇偶性不变),才能满足它是一个好的数组,而我们分的块刚好满足:每相邻的两块奇偶性都不同而每块内都相同。

所以块内合并是最优解。但是如果就按这么做,那太麻烦了。我们只需要判断,每个块内的分界线就行了,即,相邻的两个数奇偶性相同,那么计数器++。

代码

#include<iostream>
using namespace std;
#define ll long long
#define int long long
#define endl "\n"
int n,m,k;
int a[105];
void init(){
    
}
signed main(){
    init();
    int T;
    cin >> T;
    while (T --){
        cin >> n;
        for (int i = 1 ; i <= n ;i ++) cin >> a[i];
        int cnt = 0;
        for (int i = 1 ; i < n; i ++) {
            if (a[i] % 2 == a[i + 1] % 2) cnt ++;
        }
        cout << cnt << endl; 
    }
    return 0;
}

B - Emordnilap

俗话说:暴力出奇迹,打表进省一
首先,这道题的T是 1 0 5 10^5 105 n n n也是 1 0 5 10^5 105,所以你的复杂度只支持 O ( T ) O(T) O(T) 或者 O ( T l o g n ) O(T log n) O(Tlogn)
这题题面一看 l o g n log n logn就不可能。所以只能 O ( T ) O(T) O(T)
顶多加个预处理。
首先我们先找一找规律
打表代码:
下面是n=4的全排列的代码

    freopen("A.in","w",stdout);
    for (int i = 1 ; i <= 4; i ++) {
        for (int j = 1 ; j <= 4 ; j ++) {
            for (int k = 1 ; k <= 4 ; k ++) {
                for (int p = 1 ; p <= 4 ; p ++) {
                    if (i == j || j == k || i == k || i == p || j == p || k == p) continue;
                    cout << 4 << " " << i << " " << j << " " << k << " " << p << endl;
                }
            }
        }
    }

根据题意求逆序对。
A.in

4 1 2 3 4
4 1 2 4 3
4 1 3 2 4
4 1 3 4 2
4 1 4 2 3
4 1 4 3 2
4 2 1 3 4
4 2 1 4 3
4 2 3 1 4
4 2 3 4 1
4 2 4 1 3
4 2 4 3 1
4 3 1 2 4
4 3 1 4 2
4 3 2 1 4
4 3 2 4 1
4 3 4 1 2
4 3 4 2 1
4 4 1 2 3
4 4 1 3 2
4 4 2 1 3
4 4 2 3 1
4 4 3 1 2
4 4 3 2 1

A.in 里面是 上一份代码的输出

    freopen("A.in" , "r" , stdin);
    while (cin >> n) {
        if (n == 0) return 0;
        for (int i = 1 ; i <= n ; i ++) {
            cin >> a[i];
            a[2 * n + 1 - i] = a[i]; // 按照题目中处理,将他的反数组也放入a数组
        }
        int cnt = 0;
        for (int i = 1 ; i <= 2 * n ; i ++) {
            for (int j = i + 1 ; j <= 2 * n ; j ++) {
                cnt += (a[i] > a[j]);
            }
        }
        cout << cnt << endl; 
    }

这一份打表程序就是求逆序对。
输出:

12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12
12

于是,我们得出结论:对于题目来说,答案等于 n n n的逆序对个数 × \times × 全排列个数。因为逆序对个数都是相同的。
如果这样,那我们可以先预处理 n ! n! n!,然后再对 1 , 2 , … , n , n , n − 1 , n − 2 , … , 2 , 1 1,2,\dots,n,n,n-1,n-2,\dots ,2,1 1,2,,n,n,n1,n2,,2,1 进行逆序对求解。
但是:这个点复杂度为 O ( T n ) O(T n) O(Tn),不够优。
那咋整?
还能咋整,继续找规律。
于是,我们把第一个打表程序改一下。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
void init(){
    
}
int a[N];
signed main(){
    init();
    freopen("A.in" , "w" , stdout);
    for (int i = 1 ; i <= 10 ; i ++) {
        cout << i << " ";
        for (int j = 1 ; j <= i ; j ++) cout << j << " ";
        cout << endl; 
    }
    return 0;
}

A . i n : A.in: A.in:

1 1 
2 1 2 
3 1 2 3 
4 1 2 3 4 
5 1 2 3 4 5 
6 1 2 3 4 5 6 
7 1 2 3 4 5 6 7 
8 1 2 3 4 5 6 7 8 
9 1 2 3 4 5 6 7 8 9 
10 1 2 3 4 5 6 7 8 9 10 

第二个打表程序的输出为:

0
2
6
12
20
30
42
56
72
90

所以,发现规律没有?第i个逆序对个数为 i × ( i − 1 ) i \times (i - 1) i×(i1)
所以最后的答案为: n ( n − 1 ) × n ! n(n - 1) \times n! n(n1)×n!
n ! n! n!可以预处理, a i = a i − 1 ∗ i a_i = a_{i-1} * i ai=ai1i

#include<bits/stdc++.h>
using namespace std;
#define N 500005
const long long mod = 1e9 + 7;
#define int long long
#define endl "\n"
int a[N];
signed main(){
    int n;
    int T;
    a[1] = 1;
    for (int i = 2 ; i <= 1e5 + 5 ; i ++) {
        a[i] = (a[i - 1] * i) % mod;
    }
    cin >> T;
    while (T --){
        cin >> n;
        cout << (n - 1) * n % mod * a[n] % mod << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值