感受有趣的一道計數,實際上不難c++
感受很久沒用這種技巧了,致使我還在錯誤的道路上想了很久。。。spa
觀察題目性質,能夠發現就是左邊第一次出現兩遍的數字的位置\([i,n]\)是一個合法的次級子串code
右邊第一次出現兩遍的數字的位置\([1,j]\)是一個合法的次級子串,兩邊取maxget
且最長次級子串必定和首尾相連,至少出現兩遍的子序列必定是次級子串的最後一個字符出現兩遍和它的前\(|s| - 1\)個字符構成的string
這道題就是用至多長度爲\(n\)的減去至多長度爲\(n - 1\)的it
因此咱們如今考慮如何算至多長度爲\(n\)的class
首先若是長度小於等於\(n+1\)的串,必定次級子串長度至多爲\(n\),這是一個等比數列求和date
而後考慮長度爲\(n + 1 + i\)的串,很容易發現\(i <= K\),由於一旦超過\(K\),前\(n + 1\)個字符的後面就會出現至少兩個相同的字母技巧
那麼分兩種狀況考慮,一種是\(n + 1 > i\)db
那麼這個\(n + 1 + i\)的串前\(n + 1 - i\)個和後\(n + 1 - i\)個都必須有限制,第一條是左邊的數兩兩不一樣,右邊的數兩兩不一樣,左邊限制是不能和左數第\(n + 2 - i\)個相同,右邊限制是不能和右數第\(n + 2 - i\)個相同。
這個組合數算一算就行了,不難
另外一種狀況是\(n + 1 <= i\)
那麼就是前\(i + 1\)個必須兩兩不一樣,而後後\(n\)個也要兩兩不一樣,可是後\(n\)個能夠和前\(n\)個相等,和\([n + 1,i + 1]\)不相等,這也是簡單的排列組合
總之就是想到至多的那個容斥基本就會了……
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define eps 1e-10 #define ba 47 #define MAXN 200005 //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; typedef double db; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 +c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 998244353; int fac[MAXN],invfac[MAXN]; int N,K; int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } void update(int &x,int y) { x = inc(x,y); } int C(int n,int m) { if(n < m) return 0; else return mul(fac[n],mul(invfac[m],invfac[n - m])); } int fpow(int x,int c) { int res = 1,t = x; while(c) { if(c & 1) res = mul(res,t); t = mul(t,t); c >>= 1; } return res; } int getsum(int n,int q) { if(n <= 0) return 0; if(q == 1) return n; int t = inc(1,MOD - fpow(q,n + 1)); t = mul(t,fpow(1 + MOD - q,MOD - 2)); update(t,MOD - 1); return t; } int query(int n) { if(n == 0) return 0; int res = getsum(n,K); for(int i = 1 ; i <= K ; ++i) { int tmp = 0; if(n > i) { update(tmp,fpow(K,n - i)); int t = mul(C(K - 1,i),fac[i]); t = mul(t,t); tmp = mul(tmp,t); } else if(n <= i) { int t = mul(C(K,i + 1),fac[i + 1]); int h = mul(C(K - (i - n + 2),n - 1),fac[n - 1]); update(tmp,mul(t,h)); } update(res,tmp); } return res; } void Solve() { read(N);read(K); out(inc(query(N + 1),MOD - query(N)));enter; } int main(){ #ifdef ivorysi freopen("f1.in","r",stdin); #endif fac[0] = 1; for(int i = 1 ; i <= 200000 ; ++i) fac[i] = mul(fac[i - 1],i); invfac[200000] = fpow(fac[200000],MOD - 2); for(int i = 199999 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1); int T; read(T); for(int i = 1 ; i <= T ; ++i) Solve(); }