Codeforces 라운드 # 602 (사업부. 2 Technocup 2,020 토너먼트 3 기준) F2. 시험 233 (하드 버전) DP에 대한 잘못된 대답 数学

F2. 테스트 (233)에 대한 오답 (하드 버전)

여러분의 프로그램은 다시 실패. 이번에는 "테스트 (233)에 잘못된 답을"얻는다
.
이 문제의 열심히 버전입니다. 이 버전, 1≤n≤2⋅105합니다. 당신이 그것을 잠긴 경우이 문제를 해킹 할 수 있습니다. 그러나 당신은 당신이 두 문제 잠긴 경우에만 이전 문제를 해킹 할 수 있습니다.

문제는 n은 하나의 선택 - 질문을 마무리하는 것입니다. 질문의 각각은 K 옵션이 포함되어 있습니다, 단지 그들 중 하나는 올바른 것입니다. i 번째 질문에 대한 답변은 하이이고, 난 하이 인 질문의 답, 당신은 1 포인트를 적립 경우는 true, 그렇지 않은 경우, 당신은이 질문에 대해 0 포인트를 적립. 값은 H2가, ..., HN이 문제에서 당신에게 잘 알려져있다, H1.

그러나, 당신은 당신의 프로그램에서 실수 있습니다. 그것은 대답을 시계 방향으로 이동! 답변 원에 기록 된 모든 N을 고려하십시오. 인해 프로그램에서 실수로, 그들은 주기적으로 하나씩 이동합니다.

공식적으로, 실수는 질문 imodn + 1에 대한 질문 내가 대한 답을 이동합니다. 이 질문 2 질문 1에 대한 답을 이동 그래서, 질문 3에 대한 질문 2에 대한 답변을 ... 질문 1에 대한 질문 n에 대한 대답.

우리는 모두 함께 n 개의 답변 응답 소송을 호출합니다. 총 KN 가능한 대답 정장이 있습니다.

1 시계 방향으로 이동 한 후, 새로운 대답 정장의 포인트의 총 수는 이전의 점의 수보다 확실히 큰 : 당신은 많은 응답 정장은 다음과 같은 조건을 만족하는 방법을 궁금해하고 있습니다. 당신은 대답은 998,244,353 모듈로 찾을 필요가있다.

예를 들어, = 5, 그리고 당신의 대답 정장 N 경우 = [1,2,3,4,5]를,이 때문에 실수 [5,1,2,3,4] = A '로 제출 한 것입니다. 정답 정장 H = 5,2,2,3,4], A는 1 점을 얻는다 응답 양복 응답 세트 A를가 '4 점을 얻는다. 4> (1)는, 응답 슈트 ​​A는 = 1,2,3,4,5]을 계산한다.

입력

질문의 수와 각 질문에 대한 가능한 답변의 수 - 첫 번째 줄에는 두 개의 정수 N, K (1≤n≤2⋅105, 1≤k≤109)가 포함되어 있습니다.

다음 줄은 포함 n은 정수 H2, ..., HN (1≤hi≤k), H1 - 질문에 대한 답변을.

산출

출력 한 정수 : 주어진 조건을 만족하는 답변 정장의 수는 998,244,353 모듈로.

입력
3 3
1 3 1
출력
9
입력
5 5
1 4 2 2
출력
1,000
입력
6 2
1 1 2 2 1 1
출력
(16)

노트

첫 번째 예를 들면, 유효 응답 슈트는 [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 개의 답변이 있습니다,하지만 당신은 바보 이제, 첫 번째 질문에 대한 답은 두 번째 질문, 두 번째 질문은 세 번째 질문에 언급 된, 두 번째 질문은 첫 번째 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 종류 동일하게 유지됩니다.


하드 버전은 우리가 ^의 반대를 어떻게 우리가 알고있는 말을 마지막 ANS를 변환하는 변환 프로그램 이전에 같은 점수를 가지고, 다음 k로 원하는 N-ANS 프로그램 변경의 수의 변환 점수를 나타냅니다.

전방 및 높은 변환 분획과 프로그램 번호에 높은 점수를 변환 대칭성 때문에, 최종 응답이 있어야하므로, 동일 (K ^ N-ANS) / 2

그것은 무엇을 채우기 중요하지 않기 때문에 그런 다음이 ANS에서는 같은 단어가 이해가되지 않기 때문에 [I]은! = 번호 시간의 [내가 + 1] NUM 지금 시간을 가정하고, 그것을 수행하는

우리는 위치 +1의 개수를 열거 C (NUM 난)이 동일한 제 i-1 (NUM-1, ⅰ) C는, NUM-2I 다른 포지션의 선택이이 K-2 (- K- 2) ^ (NUM-2I), 나머지 N-NUM 선택 위치) K K ^ (N-NUM있다.

다음 i + 1 번 위치의 프로그램의 수는 실제로는 C이다 (NUM, ⅰ) 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;
}

추천

출처www.cnblogs.com/qscqesze/p/11925147.html