F2. Wrong Answer on test 233 (Hard Version)
Your program fails again. This time it gets "Wrong answer on test 233"
.
This is the harder version of the problem. In this version, 1≤n≤2⋅105. You can hack this problem if you locked it. But you can hack the previous problem only if you locked both problems.
The problem is to finish n one-choice-questions. Each of the questions contains k options, and only one of them is correct. The answer to the i-th question is hi, and if your answer of the question i is hi, you earn 1 point, otherwise, you earn 0 points for this question. The values h1,h2,…,hn are known to you in this problem.
However, you have a mistake in your program. It moves the answer clockwise! Consider all the n answers are written in a circle. Due to the mistake in your program, they are shifted by one cyclically.
Formally, the mistake moves the answer for the question i to the question imodn+1. So it moves the answer for the question 1 to question 2, the answer for the question 2 to the question 3, ..., the answer for the question n to the question 1.
We call all the n answers together an answer suit. There are kn possible answer suits in total.
You're wondering, how many answer suits satisfy the following condition: after moving clockwise by 1, the total number of points of the new answer suit is strictly larger than the number of points of the old one. You need to find the answer modulo 998244353.
For example, if n=5, and your answer suit is a=[1,2,3,4,5], it will submitted as a′=[5,1,2,3,4] because of a mistake. If the correct answer suit is h=[5,2,2,3,4], the answer suit a earns 1 point and the answer suite a′ earns 4 points. Since 4>1, the answer suit a=[1,2,3,4,5] should be counted.
Input
The first line contains two integers n, k (1≤n≤2⋅105, 1≤k≤109) — the number of questions and the number of possible answers to each question.
The following line contains n integers h1,h2,…,hn, (1≤hi≤k) — answers to the questions.
Output
Output one integer: the number of answers suits satisfying the given condition, modulo 998244353.
Examples
input
3 3
1 3 1
output
9
input
5 5
1 1 4 2 2
output
1000
input
6 2
1 1 2 2 1 1
output
16
Note
For the first example, valid answer suits are [2,1,1],[2,1,2],[2,1,3],[3,1,1],[3,1,2],[3,1,3],[3,2,1],[3,2,2],[3,2,3].
題意
現在有n道題,每道題有k個答案,但是你現在犯傻了,把第一題的答案交到了第二題,第二題交到了第3題,第k題交到了第(k%n)+1題的位置上去。
現在想知道,有多少種填答案的方案,可以使得交換后的正確數量多於交換前的正確數量。
題解
數據范圍小的話,dp[i][j]表示現在考慮到了第i題,交換后比交換前多得j分。
那么如果h[i]==h[i+1]的話,dp[i][j]=dp[i-1][j],因為無論如何填什么正確得個數都不會變。
其他情況 dp[i][j] = dp[i-1][j+1]+dp[i-1][j-1]+(k-2)dp[i-1][j],有一種情況是之前對了,轉換后錯了;之前錯了,轉換后對了;其他k-2種答案都保持不變。
hard version我們要反着做,假設我們知道最后轉換后和轉換前分數一樣得方案數為ans的話,那么k^n-ans表示的是轉換后得分發生改變的方案數。
又因為轉換前分數高和轉換后分數高的方案數是一樣的,因為對稱,所以最后答案一定是 (k^n-ans)/2
那么這個ans怎么做呢,假設現在h[i]!=h[i+1]的個數為num個,因為相同的話沒有意義,因為填什么都無所謂
我們枚舉+1的位置有多少個,C(num,i);同樣的-1也得i個C(num-i,i),其他num-2i個位置有k-2種選擇(k-2)^(num-2i),剩下n-num個位置都有k個選擇k^(n-num)。
那么i個+1位置的方案數其實就是C(num,i)C(num-i,i)(k-2)^(num-2i)k^(n-num),最后用所有的方案數減去他再除以2就完事。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005;
const int mod = 998244353;
int h[maxn];
long long dp[maxn][maxn*2],base=2003,k,n;
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
if(k==1){
cout<<"0"<<endl;
return 0;
}
dp[0][base]=1;
for(int i=1;i<=n;i++){
for(int j=base-2000;j<=base+2000;j++){
if(h[i]==h[i%n+1]){
dp[i][j]=dp[i-1][j]*k%mod;
}else{
dp[i][j]=(dp[i-1][j+1]+dp[i-1][j-1]+dp[i-1][j]*(k-2))%mod;
}
}
}
long long ans = 0;
for(int i=1;i<=n;i++){
ans=(ans+dp[n][base+i])%mod;
}
cout<<ans<<endl;
}
#include<bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
const int maxn = 2e5+7;
int n,k,h[maxn];
long long powmod(long long a,long long b){
if(b==0)return 1;
return b%2==0?powmod(a*a%mod,b/2):powmod(a*a%mod,b/2)*a%mod;
}
long long fac[maxn],inv[maxn];
long long C(int a,int b){
if(b<0||b>n)return 0;
return (fac[a]*inv[b]%mod)*inv[a-b]%mod;
}
int main(){
fac[0]=inv[0]=1;
for(int i=1;i<maxn;i++){
fac[i]=i*fac[i-1]%mod;
inv[i]=powmod(i,mod-2)*inv[i-1]%mod;
}
cin>>n>>k;
if(k==1){
cout<<"0"<<endl;
return 0;
}
for(int i=0;i<n;i++)
cin>>h[i];
int num = 0;
h[n]=h[0];
for(int i=0;i<n;i++){
if(h[i]!=h[i+1])num++;
}
long long ans = 0;
for(int i=0;i*2<=num;i++){
long long tmp = C(num,i)*C(num-i,i)%mod*powmod(k-2,num-2*i)%mod*powmod(k,n-num);
ans=(ans+tmp)%mod;
}
cout<<((powmod(k,n)-ans+mod)*inv[2])%mod<<endl;
}