链接:1004 Distinct Sub-palindromes
T T T 组输入
长度为 n n n 的字符串 s s s,其中 s s s 只包含小写字母;
求 s s s 中不同的回文子串数量最少的串的个数。
串长 n n n | 回文子串数 | 样例 s s s |
---|---|---|
1 | 1 | a a a |
2 | 2 | a a aa aa, a b ab ab |
3 | 3 | a a a aaa aaa, a a b aab aab, a b c abc abc |
4 | 3 | a b c a abca abca |
5 | 3 | a b c a b abcab abcab |
可见:当 n ≥ 3 n \ge 3 n≥3 时, s s s 是以不同的3个小写字母作为循环节的串;当循环节确定时,剩余的 n − n / 3 n - n / 3 n−n/3 个小写字母同时确定。
当 n < 3 n < 3 n<3时, a n s = p o w ( 26 , n ) ans = pow(26, n) ans=pow(26,n);
当 n ≥ 3 n \ge 3 n≥3时, a n s = 26 ∗ 25 ∗ 24 ans = 26 * 25 * 24 ans=26∗25∗24。
#include
#include
using namespace std;
const long long MOD = 998244353;
long long ksm(long long n, long long p, long long c)
{
if (c == 1)
return 0;
long long ans = 1;
long long thi = n % c;
while (p)
{
if (p & 1)
{
ans = ans * thi % c;
}
p >>= 1;
thi = thi * thi % c;
}
return ans;
}
int main(void)
{
int t, n;
cin >> t;
while (t--)
{
cin >> n;
if (n <= 3)
cout << ksm(26, n, MOD) << endl;
else
cout << 26 * 25 * 24 << endl;
}
return 0;
}
链接:1005 Fibonacci Sum
作弊器
T T T组输入
F i b o n a c c i Fibonacci Fibonacci 数列: F ( 0 ) = 0 F ( 1 ) = 1 , F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(0) = 0 \quad F(1) = 1 \quad, F(n) = F(n - 1) + F(n - 2) F(0)=0F(1)=1,F(n)=F(n−1)+F(n−2)
给定 N , C , K ( 1 ≤ N , C ≤ 1 0 18 , 1 ≤ K ≤ 1 0 5 ) N, C, K (1 ≤ N, C ≤ 10^{18},1 ≤ K ≤ 10^5) N,C,K(1≤N,C≤1018,1≤K≤105) ,求 F 0 k + F c k + ⋯ + F n c k F_0^k + F_c^k + \dots + F_{nc}^k F0k+Fck+⋯+Fnck
输出结果对 1 e 9 + 7 1e9 + 7 1e9+7 取模
感觉榜就是被这题带歪的 应该是我数论太菜了
F i b o n a c c i Fibonacci Fibonacci 通项: F ( n ) = 1 5 [ ( 1 + 5 2 ) n − 1 − 5 2 ) n ] F(n) = \dfrac{1}{\sqrt{5}} [(\dfrac{1 + \sqrt{5}}{2})^n - \dfrac{1 - \sqrt{5}}{2})^n] F(n)=51[(21+5)n−21−5)n]
二次剩余: x 2 ≡ 5 ( m o d 1 e 9 + 7 ) x^2 \equiv 5 (mod \ 1e9 + 7) x2≡5(mod 1e9+7),的一个解 x = 383008016 x = 383008016 x=383008016
对 F ( n ) F(n) F(n) 进行二项展开,合并同类项后预处理所有的二项式系数
每个 c a s e case case 中使用快速幂处理 a i r a^{ir} air 与 b i r b^{ir} bir
AC 变 TLE ?
#include
#include
#include
using namespace std;
typedef long long ll;
const int P = 1000000009;
const int INV2 = 500000005;
const int SQRT5 = 383008016;
const int INVSQRT5 = 276601605;
const int A = 691504013;
const int INVA = 691504012;
const int B = 308495997;
const int N = 100005;
ll n, c, K;
ll fac[N], inv[N];
ll pa[N], pb[N];
inline void Pre(int n)
{
fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i % P;
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = (P - P / i) * inv[P % i] % P;
inv[0] = 1;
for (int i = 1; i <= n; i++)
inv[i] = inv[i] * inv[i - 1] % P;
}
inline ll C(int n, int m)
{
return fac[n] * inv[m] % P * inv[n - m] % P;
}
// 计算组合数
inline ll Pow(ll a, ll b)
{
ll ret = 1;
for (; b; b >>= 1, a = a * a % P)
if (b & 1)
ret = ret * a % P;
return ret;
}
// 快速幂
inline void Init(int n)
{
pa[0] = 1;
long long cA = Pow(A, c);
long long cB = Pow(B, c);
for (int i = 1; i <= n; i++)
pa[i] = pa[i - 1] * cA % P;
pb[0] = 1;
for (int i = 1; i <= n; i++)
pb[i] = pb[i - 1] * cB % P;
}
inline ll Inv(ll x)
{
return Pow(x, P - 2);
}
// 费马小定理
inline void Solve()
{
ll Ans = 0;
for (int j = 0; j <= K; j++)
{
ll t = pa[K - j] * pb[j] % P, tem;
tem = t == 1 ? (n % P) : (t * (Pow(t, n) - 1 + P) % P * Inv(t - 1) % P);
if (~j & 1)
Ans += C(K, j) * tem % P, Ans %= P;
else
Ans += P - C(K, j) * tem % P, Ans %= P;
}
Ans = Ans * Pow(INVSQRT5, K) % P;
printf("%lld\n", Ans);
}
inline void Add(int &u, int v) {
u += v;
if (u >= P) u -= P;
}
int main()
{
int T;
Pre(100000);
scanf("%d", &T);
while (T--)
{
scanf("%lld%lld%lld", &n, &c, &K);
// Init(K);
// Solve();
// STD code below:
int DD = (long long)Pow((long long)INVA * B % P, c) % P;
int q = Pow(Pow(A, c), K);
int n1 = (n + 1) % P;
int n2 = (n + 1) % (P - 1);
int Q = Pow(q, n2);
int D = Pow(DD, n2);
int ans = 0;
for (int i = 0; i <= K; i++) {
int cur = C(K, i);
if (i & 1) cur = P - cur;
if (q == 1) Add(ans, (long long)cur * n1 % P);
else Add(ans, (long long)cur * (Q + P - 1) % P * Pow(q-1, P-2) % P);
q = (long long)q * DD % P;
Q = (long long)Q * D % P;
}
ans = ans * Pow(INVSQRT5, K) % P;
printf("%lld\n", ans);
}
return 0;
}
链接:1009 Leading Robots
按照 a a a 从小到大排序, a a a 相同则按 p p p 从小到大排序
单调栈维护所有 p p p 最大的机器人
显然, t = 0 t = 0 t=0 时, p 0 p_0 p0最大的进栈; t → + ∞ t \to + \infin t→+∞ 时, a m a x a_{max} amax 必然成为 p p p 最大的机器人
机器人的位置满足 p ( t ) = 1 2 a t 2 + p 0 p(t) = \frac{1}{2} a t^2 + p_0 p(t)=21at2+p0
若 r o b o t i robot_i roboti 超过 r o b o t t o p robot_{top} robottop,有:
p i = p t o p p_i = p_{top} pi=ptop, a i > a t o p a_i > a_{top} ai>atop
t i = t t o p = 2 ⋅ p i a i t_i = t_{top} = \sqrt{\dfrac{2 \cdot p_i}{a_i}} ti=ttop=ai2⋅pi
如果 r o b o t i robot_i roboti 追赶上 r o b o t t o p robot_{top} robottop 所需要的时间 t i t_i ti少于 r o b o t t o p robot_{top} robottop 追赶上前一个栈顶元素的时间 t t o p t_{top} ttop,则 r o b o t t o p robot_{top} robottop 出栈。
#include
using namespace std;
const int MAXN = 5e4 + 7;
const double eps = 1e-12;
int T;
int n;
int ans;
struct Robot
{
long long acc;
long long pos;
double t;
bool flg; // Check Equal
Robot(){};
Robot(long long a, long long p): acc(a), pos(p) {}
bool operator < (const Robot& b)
{
if (b.acc == acc)
return pos < b.pos;
return acc < b.acc;
}
bool operator == (const Robot& b)
{
return (acc == b.acc && pos == b.pos);
}
}rbt[MAXN];
stack<Robot> st;
int main(void)
{
// freopen("1009.in", "r",stdin);
// freopen("1009.out", "w", stdout);
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%lld%lld", &rbt[i].acc, &rbt[i].pos);
rbt[i].t = 0;
rbt[i].flg = true;
}
sort(rbt + 1, rbt + n + 1);
for (int i = 1; i <= n; ++i)
{
if (st.size() == 0)
{
st.push(rbt[i]);
continue;
}
if (rbt[i] == st.top())
{
st.top().flg = false;
rbt[i].flg = false;
rbt[i].t = st.top().t;
st.push(rbt[i]);
continue;
}
while (!st.empty())
{
Robot now = st.top();
if (rbt[i].pos >= now.pos && rbt[i].acc >= now.acc)
{
st.pop();
continue;
}
long long dp = abs(rbt[i].pos - now.pos);
long long da = abs(rbt[i].acc - now.acc);
double t = sqrt((double)2 * dp / da);
rbt[i].t = t;
if (t <= now.t + eps)
st.pop();
else break;
}
st.push(rbt[i]);
}
ans = 0;
while (!st.empty())
{
if (st.top().flg)
ans++;
st.pop();
}
printf("%d\n", ans);
}
return 0;
}
链接:1006 Finding a MEX
链接:1011 Minimum Index
L y n d o n Lyndon Lyndon 分解
对与字符串 t 1 … i t_{1 \dots i} t1…i的每一个前缀子串的 L y n d o n Lyndon Lyndon 串已知的情况,很好解决;
字符比较 | 结论 |
---|---|
t [ i ] = = t [ i + 1 ] t[i] == t[i + 1] t[i]==t[i+1] | t 1 … i + 1 t_{1 \dots i + 1} t1…i+1 仍为 L y n d o n Lyndon Lyndon 串, a n s [ i + 1 ] = a n s [ i ] ans[i + 1] = ans[i] ans[i+1]=ans[i] |
t [ i ] < t [ i + 1 ] t[i] < t[i + 1] t[i]<t[i+1] | t 1 … i + 1 t_{1 \dots i + 1} t1…i+1 仍为 L y n d o n Lyndon Lyndon 串, a n s [ i + 1 ] = a n s [ i ] ans[i + 1] = ans[i] ans[i+1]=ans[i] |
t [ i ] > t [ i + 1 ] t[i] > t[i + 1] t[i]>t[i+1] | t 1 … i + 1 t_{1 \dots i + 1} t1…i+1 不为 L y n d o n Lyndon Lyndon 串, a n s [ i + 1 ] = i + 1 ans[i + 1] = i + 1 ans[i+1]=i+1 |
显然,我们可以递推的求得每一个位置上的 a n s ans ans,计算输出 s u m sum sum 即可
#include
using namespace std;
const int MAXN = 1e7 + 7;
const int MOD = 1e9 + 7;
int t;
long long sum;
struct LyndonWord
{
string str;
int ans[MAXN];
void lyndon()
{
int i = 0;
ans[0] = 1;
// Index Start from 0
while (i < str.length())
{
int j = i;
int k = i + 1;
ans[k] = k + 1;
while (k < str.length() && str[j] <= str[k])
{
if (str[j] == str[k])
{
ans[k] = ans[j] + k - j;
j++;
}
else
{
j = i;
ans[k] = i + 1;
}
k++;
}
while (i <= j)
{
i += k - j;
// Lyndon String Right Most Pos
ans[k] = i + 1;
}
}
}
}lyn;
int main(void)
{
// freopen("1011.in", "r", stdin);
// freopen("1011.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> t;
while (t--)
{
cin >> lyn.str;
lyn.lyndon();
long long tmp = 1;
sum = 0;
for (int i = 0; i < lyn.str.length(); ++i)
{
sum += ((long long) lyn.ans[i] * tmp) % MOD; sum %= MOD;
tmp *= 1112; tmp %= MOD;
}
cout << sum << endl;
}
}
链接:1012 Mow