2020 HDU Multi-University Training Contest 1

2020 HDU Multi-University Training Contest 1

过题
1004 Distinct Sub-palindromes

链接: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
11 a a a
22 a a aa aa, a b ab ab
33 a a a aaa aaa, a a b aab aab, a b c abc abc
43 a b c a abca abca
53 a b c a b abcab abcab

可见:当 n ≥ 3 n \ge 3 n3 时, s s s 是以不同的3个小写字母作为循环节的串;当循环节确定时,剩余的 n − n / 3 n - n / 3 nn/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 n3时, a n s = 26 ∗ 25 ∗ 24 ans = 26 * 25 * 24 ans=262524

代码
#include <iostream>
#include <algorithm>
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

链接: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(n1)+F(n2)

  • 给定 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(1N,C1018,1K105) ,求 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)=5 1[(21+5 )n215 )n]

  • 二次剩余: x 2 ≡ 5 ( m o d   1 e 9 + 7 ) x^2 \equiv 5 (mod \ 1e9 + 7) x25(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

代码

ACTLE

#include <cstdio>
#include <cstdlib>
#include <algorithm>
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

链接:1009 Leading Robots

题意
  • T T T 组输入
  • N ( 0 < N ≤ 50000 ) N(0 < N≤ 50000) N(0<N50000) 个加速度为 a a a,初始位置为 p p p 的机器人 $ (0 < p,a < 2^{31})$
  • 求对于任意时刻 p p p最大且唯一的机器人数
思路
  • 按照 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=ai2pi

    如果 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 <bits/stdc++.h>
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

链接:1006 Finding a MEX

1011 Minimum Index

链接:1011 Minimum Index

题意
  • 在给定长度为 n   ( 1 ≤ n ≤ 2 e 7 ) n \ (1 \le n \le 2e7) n (1n2e7) 字符串 t t t 的每一个前缀字符串 t 1 … i t_{1 \dots i} t1i 找到字典序最小的后缀子串 t j ⋯ i t_{j \cdots i} tji,为 a n s [ i ] ans[i] ans[i]
  • 输出 ( ∑ 0 ≤ i ≤ n − 1 a n s [ i ] ⋅ 111 2 i ) m o d      1 e 9 + 7 (\sum\limits_{0 \le i \le n - 1} ans[i] \cdot 1112^{i})\mod \ 1e9 + 7 (0in1ans[i]1112i)mod 1e9+7
思路
  • L y n d o n Lyndon Lyndon 分解

    对与字符串 t 1 … i t_{1 \dots i} t1i的每一个前缀子串的 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} t1i+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} t1i+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} t1i+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 <bits/stdc++.h>
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

链接:1012 Mow

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值