2020牛客多校第一場 F J
F題 Infinite String Comparision
本場的簽到題
題意:給兩個字串 \(a\) 和 \(b\)。\(a\) 和 \(b\) 重複無窮遍構成字串 \(a^\infty\) 和 \(b^\infty\),判斷 \(a^\infty\) 和 \(b^\infty\)的字母序大小。
思路:最開始想的是將 \(a\) 和 \(b\) 補充到它們長度的最小公倍數或者用模作為下標進行比較,由於資料範圍 \(a\)、\(b\) 長度在 \(10^5\),這種做法會tle。
之後的想法是將長的那個字串延長一倍,然後短的字串補到和長的一樣長,再做比較。
賽後看到更簡潔的做法,\(p=a+b\)
題解:
Compare the string \(a^\infty\) and \(b^\infty\) directly
By the Periodicity Lemma, if there is no mismatches in the first \(a + b - gcd(a, b)\) characters, the two string are identical
Periodicity Lemma
假設一個字串 \(S\) 有迴圈節 \(p\) 和 \(q\) 並且滿足 \(p + q \leqslant |S| + gcd(p, q)\),那麼 \(gcd(p, q)\) 也是一個迴圈節。
定理的證明:https://zhuanlan.zhihu.com/p/85169630
\(a\) 和 \(b\) 分別為 \(a^\infty\) 和 \(b^\infty\) 的迴圈節,如果 \(a^\infty\) 和 \(b^\infty\) 相等,設 \(S=a^\infty=b^\infty\),則 \(a\),\(b\) 為 \(S\) 的迴圈節。
\(|S|=\infty\),所以 \(a + b \leqslant |S| + gcd(a, b)\) 成立,\(gcd(a, b)\) 也是一個迴圈節,\(a^\infty\) 和 \(b^\infty\)
則只需要比較前 $$a + b - gcd(a, b)$$ 個字母,就可以判斷兩字串是否相等。
程式碼如下(直接比較a+b和b+a的做法):
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int main(){
string a, b;
while(cin>>a>>b){
string p = a + b;
string q = b + a;
if(p > q) cout<<">"<<endl;
else if(p < q) cout<<"<"<<endl;
else cout<<"="<<endl;
}
return 0;
}
(比較前\(a + b - gcd(a, b)\)個字母的做法)
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
char a[N], b[N];
int gcd(int a, int b){
return b==0?a:gcd(b, a%b);
}
int main(){
while(scanf("%s %s", a, b) == 2){
int la = strlen(a);
int lb = strlen(b);
int l = la + lb - gcd(la, lb);
int flag = 0;
for(int i = 1; i <= l; i ++ ){
if(a[i%la] > b[i%lb]){
flag = 1;
break;
}
else if(a[i%la] < b[i%lb]){
flag = -1;
break;
}
}
if(flag == 0) printf("=\n");
else if(flag == 1) printf(">\n");
else printf("<\n");
}
return 0;
}
J題 Easy Integration
題意:計算\(\int_0^1(x-x^2)^ndx\)的值,這個值可以被表示為\(\frac{p}{q}\),輸出結果\((p·q^-1)mod998244353\)。
思路:用微積分計算出上面式子的值,或者直接找規律。
題解:
The value is (n!)^2 / (2n+1)!
Detailed proof can be found in “Wallis' integrals”.
\[\int_0^1(x-x^2)^ndx\\ =\int_0^1x^n(1-x)^ndx\\ =\frac{x^n+1}{n+1}(1-x)^n|_0^1-\int_0^1\frac{x^n+1}{n+1}(-n)(1-x)^n-1\quad dx\\ =\frac{n}{n+1}\int_0^1x^{n+1}(1-x)^{n-1}dx\\ =\frac{n}{n+1}\{[\frac{x^{n+2}}{n+2}(1-x)^{n-1}]_0^1-\int_0^1\frac{x^{n+2}}{n+2}(-n+1)(1-x)^{n-2}dx\}\\ =\frac{n(n-1)}{(n+1)(n+2)}\int_0^1x^{n+2}(1-x)^{n-2}dx\\ =\frac{n(n-1)···1}{(n+1)(n+2)···2n}\int_0^1x^{2n}dx\\ =\frac{n(n-1)···1}{(n+1)(n+2)···2n}\\ =\frac{(n!)^2}{(2n+1)!} \]
程式碼如下:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int mod = 998244353;
const int N = 2e6 + 10;
const int M = 2e6;
LL fac[N], inv[N];
LL pow_mod(LL a, LL b, LL p){
LL ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
void init(){
fac[0] = 1;
for(int i = 1; i <= M; i ++ )
fac[i] = fac[i-1] * i % mod;
inv[M] = pow_mod(fac[M], mod-2, mod);
for(int i = M-1; i > 0; i --)
inv[i] = inv[i+1] * (i+1) % mod;
}
int main(){
init();
int n;
while(scanf("%d", &n) != EOF){
printf("%lld\n", fac[n] * fac[n] % mod * inv[2*n+1] % mod);
}
return 0;
}
I題正在補,圖論苦手……補完再更