1. 程式人生 > >D. New Year and the Permutation Concatenation 題解翻譯+思路解釋(官方為主,我為補充)+普通人能看得懂的程式碼(我照著思路寫的哈哈哈)

D. New Year and the Permutation Concatenation 題解翻譯+思路解釋(官方為主,我為補充)+普通人能看得懂的程式碼(我照著思路寫的哈哈哈)

傳送門:http://codeforces.com/contest/1091/problem/D

There are two types of subarrays with length n:
有兩種型別的長度為n的子序列

  • They are fully formed from one permutations.
    所組成的元素完全就是來自某一個獨立的排列
  • They are a concatenation of a k long suffix of one permutation, and a nk long prefix of the next permutation.

    一個級聯(雜交)排列,它裡面前k個元素來自某一個排列的字尾部分,後(n-k)個元素來自下一個排列的字首部分。

There are n! such subarrays of the first type, and they all have the the correct sum.
很顯然,有n!個排列是第一種型別的,且數量有n!個。因為是一個獨立的排列,所以和一定是所要求的n*(n+1)/2

Let's investigate the second type. Recall the algorithm of finding the next permutation in lexicographical order. We find the longest
讓我們探索一下第二種型別。回顧一下按字典序產生下一個排列的演算法。我們找到一段降序排列的最長字尾,定義它的長度為k
suffix that is in decreasing order, let its length be 

k.
We swap the preceding element 
x with the smallest one from the decreasing sequence larger than x,
我們把 這段字尾的前一個元素x 和 這段降序字尾中大於x又是最小的那個元素 交換。
and sort the suffix in increasing order.
然後將新字尾按升序排列。
The prefix of length 
n−k−1 is left unchanged, but all longer proper prefixes are different and also change their sum.
作為字首部分的前(n-k-1)個元素保持不動,但是任何比(n-k-1)更長的字首排列和原來的相比都不一樣了包括它們的元素和

Coming back to our problem, if the suffix of length k is in decreasing order,
迴歸正題,如果當前獨立排列的長度為k的字尾是按降序排列
than the prefix of length 
nk of the next permutation has different sum from the prefix of the same length of the current permutation,
那麼下一個排列的前(n-k)個元素就擁有了和當前排列相同長度的字首排列不同的和 (降序一定改變下一個排列前(n-k)個元素的佈局)。
hence the subarray has incorrect sum.
因此這個雜交排列的和就一定不是我們期待的n*(n+1)/2了(由於某一個相同的元素跑到下一個獨立排列的字首當中)
Conversely, if the suffix of length k is not in decreasing order, then the prefix of length 
nk of the next permutation equals to the prefix of the current permutation, and its sum is n(n+1)/2.
相反的,如果當前獨立排列的長度為k的字尾不按降序排列,下一個排列的前(n-k)個元素就和當前排列相同長度的字首排列一樣,雜交排列的和就是我們期待的n*(n+1)/2

To find the answer, we must thus subtract the number of suffixes of all permutations that are decreasing.
為了找出答案,我們一定要找出所有按照降序排列的字尾個數(長度從1到(n-1)) 
How many of them are there for a fixed k
?
如果告訴我們字尾長度是k,那麼這樣的字尾到底有多少個呢?
This is simple – we choose the first 
nk elements freely, and permute them.
很簡單,我們自由選擇前(n-k)個元素,然後讓他們進行全排列
The rest has to be sorted in a particular way.
剩下的部分需要按照降序排列
Hence the number of bad subarrays coming from a suffix of length 
k equals n!/k!.
所以無效字尾的個數(在後綴長度等於k的前提下)就是n
!/k!:

                                                 C_{n}^{k}*(n-k)!=n!/k!

Convince yourself that this approach works correctly even for the last permutation, where there is no next permutation to concatenate its suffixes with.
你還要確保這個方法能正確工作即使是字尾在最後一個獨立排列的時候,因為它後面沒有能和它的字尾連線的獨立排列了

The answer is:

其實可以這樣子推導:
考慮進第一種情況,然後把字尾問題轉化成從哪個點開始的排列可以達成目的,當然你還是要通過上面的講解來理解什麼時候能達成目的——後序是降序序列
物理上不允許作為字首的起始點的個數=(n-1)…………………………………………………………①
那麼所有可以作為字首的起始點的個數= n*n! - (n-1)…………………………………………………②
邏輯上不允許作為字首的起始點的個數= ………………③
這個公式裡為什麼要每次都減1呢?
因為降序字尾肯定是會涉及到最後一個獨立排列(剛好是全降序)裡面的,然而我們之前已經把它歸為物理不允許字首起始點了,所以要減去這種情況。
②-③ 就得到了:

This can be calculated in O(n) without the need of modular division.
我的程式碼只能做到O(n),不能做到不用取模運算。程式碼在下方:

There is also a simple recurrence counting the same answer, found by arsijo:
另一位大佬的方式:重複計數求值法

d(n)=(d(n−1)+(n−1)!−1)⋅n

接下來是我按照第一種正式的思路寫出來的程式碼:



 

/*SE:wn------王寧*/
#include <bits/stdc++.h>
using namespace std;

#define ll long long
const ll MOD = (ll)998244353;
ll n;

int main()
{
    scanf("%lld", &n);
    ll res = n;
    ll i,j,k,tmp=1;
    for(i=2;i<=n;++i) res=res*i%MOD;
    for( k=n; k>=2 ; --k )
    {
    	tmp=tmp*k%MOD;
		res=(res-tmp+MOD)%MOD;
	}
	cout<<res;
    return 0;
}

轉載請註明出處。