起点是
(
0
,
0
)
(0, 0)
(0,0),终点是
(
N
+
M
,
N
+
M
)
(N + M, N + M)
(N+M,N+M) 假设当前已经选了
x
x
x 个
A
A
A,
y
y
y 个
B
B
B. 那么当前字符串符合题意当且仅当
−
n
≤
y
−
x
≤
m
-n \le y - x \le m
−n≤y−x≤m. 因此,我们将所有最后一次从非法区域(下图空白部分)到合法区域(阴影部分)是从
y
=
x
+
n
y = x + n
y=x+n 的转移过来的非法路径(将该转移点记作
M
M
M),把所有在
y
=
x
+
n
y = x + n
y=x+n 上方的部分,以及M到终点的路径,做关于
y
=
x
+
n
y=x+n
y=x+n 的对称。
这样,所有这样的非法路径就等价于到
C
2
(
n
+
m
)
n
+
m
−
C
2
(
n
+
m
)
n
−
1
−
C
2
(
n
+
m
)
m
−
1
C_{2(n+m)}^{n+m} - C_{2(n+m)}^{n - 1}-C_{2(n+m)}^{m - 1}
C2(n+m)n+m−C2(n+m)n−1−C2(n+m)m−1.
其实很多时候这种题的套路都是做终点关于合法直线向上(向下)平移一格的对称点。
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint maxn =4010;const ll mod =1e9+7;int N, M;
ll fact[maxn], infact[maxn];
ll mod_pow(ll x, ll n){
ll res =1;while(n){if(n &1) res = res * x % mod;
x = x * x % mod;
n >>=1;}return res;}
ll C(ll n, ll m){if(m ==-1)return0;return fact[n]* infact[m]% mod * infact[n - m]% mod;}intmain(){
fact[0]= infact[0]=1;for(ll i =1; i < maxn; i++){
fact[i]= fact[i -1]* i % mod;
infact[i]= infact[i -1]*mod_pow(i, mod -2)% mod;}while(cin >> N >> M){
ll ans =((C(2*(N + M), N + M)-C(2*(N + M), N -1)-C(2*(N + M), M -1))% mod + mod)% mod;printf("%lld\n", ans);}return0;}
B. Beauty Values
题意:求每个子区间不同数的数目之和
思路:其实就是枚举每一个数在那些区间会出现。如果当前第 i 个数是从未出现过的数字,那么包含这个数字的子区间的左端点就是
[
1
:
i
]
[1:i]
[1:i],右端点就是
[
i
:
n
]
[i:n]
[i:n]。因此对答案的贡献就是
i
∗
(
n
−
i
+
1
)
i * (n - i + 1)
i∗(n−i+1). 如果之前出现过,出现的位置是 u,那么左端点是
[
u
+
1
:
i
]
[u + 1:i]
[u+1:i],右端点是
[
n
−
i
+
1
]
[n - i + 1]
[n−i+1].
#include<bits/stdc++.h>usingnamespace std;constint maxn =100010;typedeflonglong ll;int a[maxn], vis[maxn], N;intmain(){scanf("%d",&N);for(int i =1; i <= N; i++){scanf("%d",&a[i]);}
ll ans =0;for(ll i =1; i <= N; i++){if(!vis[a[i]]) ans += i *(N - i +1);else{
ans +=(ll)(N - i +1)*(i - vis[a[i]]);}
vis[a[i]]= i;}printf("%lld\n", ans);return0;}
F. Fraction Comparision
签到,注意数据范围别爆long long.
#include<iostream>#include<algorithm>#include<cstring>usingnamespace std;typedeflonglong ll;
ll x, a, y, b;intmain(){while(cin >> x >> a >> y >> b){
ll num1 = x / a, num2 = y / b;
x %= a, y %= b;if(num1 > num2)printf(">\n");elseif(num1 < num2)printf("<\n");else{if(x * b > a * y)printf(">\n");elseif(x * b < a * y)printf("<\n");elseprintf("=\n");}}return0;}
G. Gemstones
题意:可以取出一个序列中连续的三个一样的字符,然后把剩下的序列两部分合成一个。
用一个栈就可以了。
#include<bits/stdc++.h>usingnamespace std;constint maxn =100010;char stk[maxn], str[maxn];int N;intmain(){scanf("%s", str +1);
N =strlen(str +1);int tt =0;int ans =0;for(int i =1; i <= N; i++){
stk[++tt]= str[i];if(tt >=3&& stk[tt]== stk[tt -1]&& stk[tt -1]== stk[tt -2]){
tt -=3;
ans++;}}printf("%d\n", ans);return0;}