A.

题意:有1~n一排数,每天可以搬运一个东西到相邻的位置,一共搬运d天,问你1号位置最多能有多少东西

题解:肯定是贪心往1号位置搬,先从2号位置搬,再从3号位置搬,一直搬到到达第d天或者全部搬完为止

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, a[N];
void solve()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        int num = min(a[i],m/i);
        a[0]+=num;
        m-=num*i;
    }
    printf("%d\n",a[0]);
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

B.

题意:一个人要从(0,0)走到(x,0),但是每次只能走他喜欢的步数,他有n个喜欢的步长,你每次可以选择其中的一种,问你他走到(x,0)最少需要几步。

题解:分析可以发现除了x恰好等于其中一个喜欢的步数答案为1以外,其他都可以通过选择最大的步长走到,并且答案是最优的,如果x%最长的步数恰好为0那么就一直直走;否则前面直走,走到小于2倍步长斜着走即可。

就是对x向上取整

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, x, a[N];
map<int,int>H;
void solve()
{
    H.clear();
    scanf("%d%d",&n,&x);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        H[a[i]]=1;
    }
    sort(a,a+n);
    if(H[x])
        puts("1");
    else
        printf("%d\n",max(2,(x+a[n-1]-1)/a[n-1]));

}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

C.

题意:给你一个s序列,定义序列t,t满足为s的子序列,并且t的每一位下标在s中构成等差序列。询问在所有的t中,哪种序列出现次数最多。

题解:发现每增加一位都会增加一些限制,这样序列个数肯定不会多,所以我要考虑限制最少的。限制最少的肯定是仅由1个或2个字符组成的,没有任何限制,我们就找这两种就好了。单个的序列我们在遍历的时候更新即可,两个组成的序列,我们在遍历的时候用dp[i][j]记录,表示以i为开头,以字符j结尾的序列次数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
ll a[30], dp[30][30];
int main()
{
    string s;
    cin >> s;
    ll ans = 0;
    for (int i = 0; i < s.length(); i++)
    {
        for (int j = 0; j < 26; j++)
        {
            dp[j][s[i] - 'a'] += a[j];
            ans = max(ans, dp[j][s[i] - 'a']);
        }
        a[s[i] - 'a']++;
        ans = max(ans, a[s[i] - 'a']);
    }
    printf("%lld\n", ans);
    return 0;
}

D.

题意:一共有n个点和m条边,有k个特殊点,要求从中选取两个建一条边使得从1到n的最短路最大

题解:设ax为1号点到k个节点中的一个节点x的最短路径,by为n号节点到k个节点中的另一个节点y的最短路径,1号节点通过x、y路径到n的距离为ax+by+1。那么交换x、y以后,距离为ay+bx+1,要求最短路,如果是答案那么只会是min(ax+by+1,ay+bx+1),我们令ax+by+1<ay+bx+1,消掉1,交换ay和by得,ax-ay<bx-by,由此我们可以对(ax-ay)进行排序,对于每一个ax之后的每一个by都是满足ax+by<ay+bx,即为可能的答案,算出其中的最大值与不加边的最短路比较取小着即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int a[maxn], dis[2][maxn];
vector<int> G[maxn];
void bfs(int st, int idx)
{
    dis[idx][st] = 0;
    queue<int> q;
    q.push(st);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (auto v : G[u])
            if (dis[idx][v] == INF)
            {
                dis[idx][v] = dis[idx][u] + 1;
                q.push(v);
            }
    }
}

int main()
{
    memset(dis, INF, sizeof(dis));
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 0; i < k; i++)
        scanf("%d", &a[i]);
    sort(a, a + k);
    for (int i = 0; i < m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    bfs(1, 0);
    bfs(n, 1);
    vector<pii> v;
    for (int i = 0; i < k; i++)
        v.emplace_back(dis[0][a[i]] - dis[1][a[i]], a[i]);
    sort(v.begin(), v.end());
    int ans = 0, tmp = 0;
    for (int i = 0; i < v.size(); i++)
    {
        if (i)
            ans = max(ans, tmp + dis[1][v[i].second] + 1);
        tmp = max(tmp, dis[0][v[i].second]);
    }
    cout << min(dis[0][n], ans) << endl;
    return 0;
}