Contestant'. Rank 1357. Rating +14 (+264 -250).

A. LuoTianyi and the Palindrome String

题意

给定一个字符串,输出最长的非回文子串的长度。

思路

很显然,如果整个字符串是回文串,那么我们拿掉一个字符即可,长度为 \(n - 1\)

如果不是,那么整个字符串就是非回文串,长度为 \(n\)

当然,如果整个字符串都是由一个字母组成的,那么无法将其变为非回文,无解输出 \(-1\)

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 110, inf = 0x3f3f3f3f3f3f3f3f;

void solve(){
    string s;
    cin >> s;
    bool f = false;
    int n = s.size();
    for(int i=1;i<n;i++){
        if(s[0] != s[i]) f = true;
    }
    if(!f){
        cout << -1 << '\n';
        return;
    }
    for(int i=0;i<n/2;i++){
        if(s[i] != s[n - i - 1]) f = false;
    }
    cout << (f ? n - 1 : n) << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

很签到,虽然要绕一下

B. LuoTianyi and the Table

题意

给定一个 \(n \times m\) 的矩阵,以及 \(n \times m\) 个元素组成的序列。将序列中所有元素填入矩阵中,满足下面的式子最大,并输出这个最大值:

\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\left(\max\limits_{1 \le x \le i, 1 \le y \le j}a_{x,y}-\min\limits_{1 \le x \le i, 1 \le y \le j}a_{x,y}\right)\)

思路

思维题。

如果要让最大值减最小值的值最大,那么我们一定会用最大的值减去最小的值。

对于上述式子,我们不难发现,只要满足下面的两种情况,即为最大值:

  1. 左上角为最大值,其相邻两个元素为最小值和次小值;

  2. 左上角为最小值,其相邻两个元素为最大值和次大值

我们取两者的最大值即可。

时间复杂度:\(O(nm)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 110, inf = 0x3f3f3f3f3f3f3f3f;

void solve(){
    int n, m;
    cin >> n >> m;
    vector<int> a(n * m);
    for(int i=0;i<n*m;i++) cin >> a[i];
    sort(all(a));
    if(n > m) swap(n, m);
    int ans1 =
            (n * (m - 1)) * (a[n * m - 1] - a[0])
            + (n - 1) * (a[n * m - 1] - a[1]);
    int ans2 =
            (n * (m - 1)) * (a[n * m - 1] - a[0])
            + (n - 1) * (a[n * m - 2] - a[0]);
    cout << max(ans1, ans2) << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

偏思维的题捏

C. LuoTianyi and the Show

题意

给定三种操作如下:

  1. 坐在当前最左边的人的左边,如果最左边的人左边无位置,那么坐到最右边;

  2. 坐在当前最右边的人的右边,如果最右边的人右边无位置,那么坐到最左边;

  3. 坐到指定位置

现在,给定 \(n\) 个人的操作,操作用一个数字表征,其中操作 \(1\)\(-1\),操作 \(2\)\(-2\),操作 \(3\) 为一个正整数,代表坐到该位置。

如果不可以坐,那么这个人离场。

输出按任意顺序排座后最多能坐多少人。

思路

首先,重复的正整数我们直接筛去,因为不会重叠。

那么,对于第一个数,我们有两个选择:

  1. 执行操作 \(3\),对此我们可以标记操作 \(3\) 的所有下标,并枚举这些下标。既然我们确定了一个点,那么我们只能从这个点开始向左右拓展。 为计算方便,我们可以用 \(pre, suf\) 数组记录前 \(i\) 个数和后 \(n - i + 1\) 个数去掉操作 \(3\) 后有多少空位置。 那么, \(\min(pre[i], cnt_1) + \min(suf[i], cnt_2) + cnt_{12}\) 就是当前位置的答案。

  2. 一直执行操作 \(1\) 或操作 \(2\),并在经过和结束后执行操作 \(3\),那么,\(\min(\max(cnt_1, cnt_2) + cnt_{12}, m)\) 就是该选择的答案

最后,我们取最大值即可。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 110, inf = 0x3f3f3f3f3f3f3f3f;

void solve(){
    int n, m;
    cin >> n >> m;
    int cnt1 = 0, cnt2 = 0;
    vector<bool> st(m + 1);
    int cnt = 0;
    for(int i=0;i<n;i++){
        int cur;
        cin >> cur;
        if(cur == -1) cnt1 ++;
        else if(cur == -2) cnt2 ++;
        else if(!st[cur]) st[cur] = true, cnt ++;
    }
    vector<int> pre(m + 2), suf(m + 2);
    for(int i=2;i<=m;i++){
        pre[i] = pre[i - 1] + (st[i - 1] ? 0 : 1);
    }
    for(int i=m-1;i>=1;i--){
        suf[i] = suf[i + 1] + (st[i + 1] ? 0 : 1);
    }
    int ans = min(max(cnt1, cnt2) + cnt, m);
    for(int i=1;i<=m;i++){
        if(st[i]) ans = max(ans, min(pre[i], cnt1) + min(suf[i], cnt2) + cnt);
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

一开始想着确定两个点,想复杂了

D1. LuoTianyi and the Floating Islands (Easy Version)

题意

给定一棵无根树,给定整数 \(n, k\),其中 \(n\) 为节点个数,\(k\) 为标记点的个数。确定标记点放置位置后,若某些点满足到所有标记点的距离之和为所有点中最小,那么这些点符合条件。输出符合条件的点的数量的期望。

本题中,\(k_{max} = 3\)

思路

首先,\(k = 1\) 的时候很显然,标记点能确定的位置有 \(n\) 个,当标记点被确定后,距离最小的点只可能是标记点,因此期望为 \(\frac{n}{n} = 1\)

由此,\(k = 3\) 的时候也是这样,期望为 \(1\)

有趣的是,当 \(k\) 为奇数时,期望均为 \(1\),此处不给出证明。

那么,我们来考虑 \(k = 2\) 的情况:

首先,\(n\) 个点中选 \(2\) 个,很明显分母是 \(C_n^2\)

其次,如果我们 不考虑方向,那么,对于一条边,我们可以很轻松地通过 \(Dfs\) 求出其某一方向的连通块的点的个数 \(x\)

那么,这条边就被经过了 \(x(n-x)\) 次。

这是很显然的,但有趣的是这么一求,我们的答案偏小了。

不妨对着样例一模拟一遍,我们不难发现缺少了从 \(2, 3, 4\) 节点向 \(1\) 方向的边,这恰好就是 \(C_n^2\)

或者说,因为距离为 \(d\) 的两点间算上端点总共有 \(d + 1\) 个点,因而这么计算,起点或者终点对应的距离肯定有一个没被计算。

那么,最后的答案就是 \(\displaystyle{\frac{\sum_{i = 1}^n dp_i(n - dp_i) + C_n^2}{C_n^2}}\)

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 110, inf = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;

int qp(int a, int b) {
    int res = 1;
    while (b > 0) {
        if (b & 1) res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

int inv(int n) {
    return qp(n, mod - 2);
}

void solve(){
    int n, k;
    cin >> n >> k;
    vector<vector<int>> e(n + 1);
    for(int i=0;i<n-1;i++){
        int u, v;
        cin >> u >> v;
        e[u].pb(v), e[v].pb(u);
    }
    if(k % 2 == 1){
        cout << 1 << '\n';
        return;
    }
    vector<int> dp(n + 1);
    auto dfs = [&](auto self, int c, int p) -> void{
        dp[c] = 1;
        for(auto x : e[c]){
            if(x == p) continue;
            self(self, x, c);
            dp[c] += dp[x];
        }
    };
    dfs(dfs, 1, 1);
    int ans = 0;
    for(int i=1;i<=n;i++) ans = (ans + (dp[i] * (n - dp[i]) % mod)) % mod;
    ans = (ans + n * (n - 1) / 2 % mod) % mod;
    ans = ans * inv(n) % mod;
    ans = ans * inv(n - 1) % mod;
    ans = ans * 2 % mod;
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t --) solve();
}

太抽象了