codeforces 1091D New Year and the Permutation Concatenation 组合数

D. New Year and the Permutation Concatenation

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Let nn be an integer. Consider all permutations on integers 11 to nn in lexicographic order, and concatenate them into one big sequence pp . For example, if n=3n=3 , then p=[1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1]p=[1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1] . The length of this sequence will be n⋅n!n⋅n! .

Let 1≤i≤j≤n⋅n!1≤i≤j≤n⋅n! be a pair of indices. We call the sequence (pi,pi+1,…,pj−1,pj)(pi,pi+1,…,pj−1,pj) a subarray of pp . Its length is defined as the number of its elements, i.e., j−i+1j−i+1 . Its sum is the sum of all its elements, i.e., ∑jk=ipk∑k=ijpk .

You are given nn . Find the number of subarrays of pp of length nn having sum n(n+1)2n(n+1)2 . Since this number may be large, output it modulo 998244353998244353 (a prime number).

Input

The only line contains one integer nn  (1≤n≤1061≤n≤106 ), as described in the problem statement.

Output

Output a single integer — the number of subarrays of length nn having sum n(n+1)2n(n+1)2 , modulo 998244353998244353 .

Examples

Input

Copy

3

Output

Copy

9

Input

Copy

4

Output

Copy

56

Input

Copy

10

Output

Copy

30052700

Note

In the first sample, there are 1616 subarrays of length 33 . In order of appearance, they are:

[1,2,3][1,2,3] , [2,3,1][2,3,1] , [3,1,3][3,1,3] , [1,3,2][1,3,2] , [3,2,2][3,2,2] , [2,2,1][2,2,1] , [2,1,3][2,1,3] , [1,3,2][1,3,2] , [3,2,3][3,2,3] , [2,3,1][2,3,1] , [3,1,3][3,1,3] , [1,3,1][1,3,1] , [3,1,2][3,1,2] , [1,2,3][1,2,3] , [2,3,2][2,3,2] , [3,2,1][3,2,1] .

Their sums are 6 ,6, 7 ,6 ,7,5,6,6, 8 , 6 , 7 , 5 , 6 , 6 , 7 , 6 . As n(n+1)/2=6 , the answer is 9 .

题意:给你一个数n,让你求在n的全排列依次排列的序列中找到多少个区间满足区间长度为n,该区间内数的和为n*(n+1)/2。

思路:很容易想到,全排列中的每一个排列的和就是n*(n+1)/2,全排列有n!个,然后就是两个相邻排列之间可以组合的了,我们用一个固定长度为n的滑动窗口来类比所选区间,当窗口向右移动时,左边每出去一个数右边就会进去一个数,想要区间和为    n*(n+1)/2那么区间内所数必须是(1~n)的全排列,因为是全排列顺序排列,所以只可能是出去和进去的数是相同的(有多个的话这多个数顺序也必须相同的,比如:....,45 321,54123,45 123 和123 45都满足和为15 但是是顺序的全排列这是不可能出现的),终上所述只要两个相邻的全排列相同前缀的就可以满足条件,我们有假设长度为i的相同前缀,有多少长度就可以分多少个区间出来,还是由于是全排列,所以这i个也是全排列,有A(n,i)选择,剩下后面的n-i个数还是全排列,最后要确保不重不漏,确保只有长度严格为i的前缀相同,那么在相邻两个排列中第i+1个必须不同,所以第i+1位一定是剩下n-i个中的一个,需要的是两个相邻的所以有n-i-1中可行的两个相邻排列。最后三者相乘取sigma,得到结果,说的比较生硬,集体见代码。比赛的时候我真的差点就推出来了。

#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<iterator>
#include<set>
#include<map>
#include<bitset>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const double e=exp(1.0);
const double pi=acos(-1);
const double eps=1e-6;
int gcd(int a,int b)
{
	if(b==0)return a;
	return gcd(b,a%b);
}
ll quick_pow(ll a,int n)
{
	ll ans=1;
	while(n)
	{
		if(n&1)ans=(ans*a)%mod;
		n/=2;
		a=(a*a)%mod;
	}
	return ans;
}
ll fac[maxn],inv[maxn];
ll C(ll n,ll m)
{
	return ((fac[n]*inv[m])%mod*inv[n-m])%mod;
}
int main()
{
	fac[0]=1ll;
	fac[1]=1ll;
	inv[1]=1ll;
	for(int i=2;i<maxn-2;i++)
	{
		fac[i]=fac[i-1]*i%mod;
		inv[i]=quick_pow(fac[i],mod-2);
	}
	int n;
	while(scanf("%d",&n)!=EOF)
	{
	ll ans=fac[n];
	for(int i=1;i<=n-2;i++)//相邻的两个排列最后两个数一定是不同的 
	ans=(ans+i*C(n,i)%mod*fac[i]%mod*(n-i-1)%mod)%mod;
	cout<<ans<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值