A
注意题上说了,ai序列是不降序列,那么对于Σai * i来说,大的数自然是在后面更好啦。所以说至少移动k个位置,那么我们就只让他动k个位置,这样保证减少的数尽可能小,保证结果尽可能大。
那么我们首先求出最开始的ans=Σai * i 然后对k+1后的枚举
一个数字往前移动k位,对结果的影响就是:i-1-k到i-1这一段的数字统一向右移动了一位,增加的价值就是这一段的和,考虑前缀和维护即可,那么a[i]从当前位置去到了i-k,那么就应该减去a[i] * k 在加上a[i] * (i-k)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{

    int t;cin>>t;
    while(t--){
        int n,k;cin>>n>>k;
        ll ans=0;
        vector<ll> a(n+1);
        vector<ll> sum(n+1);
        for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i]*i,sum[i]=sum[i-1]+a[i];
       // cout<<ans<<endl;
        ll q=-1e18;
        for(int i=k+1;i<=n;i++){

            ll e=ans-a[i]*i+(sum[i-1]-sum[i-1-k])+a[i]*(i-k);
            q=max(q,e);
        }
        cout<<q<<endl;
    }
    return 0;
}

B
因为概率是完全相等的,那么我们就枚举每个人是第i个出发,计算出来的总和除以n即可
总路程是n * u 因为最后要除以n 所以过程量直接消掉了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    //ios::sync_with_stdio(0);
    int n;double v,u;
    cin>>n>>v>>u;
    double ans=0;
    vector<double> a,b;
    a.resize(n+1),b.resize(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ans+=1.0*u/(a[i]-v-(j-1)*b[i]);
        }
    }
    printf("%.3f",ans);
    return 0;
}

C
这题其实就是求lca(最近公共祖先)
计算出A->1的距离dist1
计算出B->C->1的距离dist2
如果dist1<dist2 也就是A先到根节点就是YES
如果dist1==dist2 我们这里要看一下lca(a,c)是不是1 如果是的话 说明他们是从根节点的两个子树过去的,在达到根节点之前不会碰到,就输出NO,如果lca!=1,因为距离还一样,他们一定会在lca(a,c)碰面 就输出YES
如果dist1>dist2 就输出NO

这题让我发现我的tarjan求lca的板子是错的。。
板子过于丑陋,仅供参考

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define me(a,x) memset(a,x,sizeof a)
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define all(x) (x).begin(), (x).end()
#define pb(a) push_back(a)
#define paii pair<int,int>
#define pali pair<ll,int>
#define pail pair<int,ll>
#define pall pair<ll,ll>
#define fi first
#define se second
const int maxn=200005;
vector<paii> e[maxn];
vector<paii> query[maxn];
bool vis[maxn];
int f[maxn],d[maxn];
int lcaa[maxn];
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
paii ans[maxn];
int q[maxn];
void lca(int root)
{
    //cout<<root<<":";
    vis[root]=1;
    f[root]=root;
    for(int i=0; i<e[root].size(); i++){
        int next=e[root][i].fi;
        if(!vis[next]){
            d[next]=d[root]+e[root][i].se;
            lca(next);
            f[next]=root;
        }
    }

    for(int i=0; i<query[root].size(); i++){

        int v=query[root][i].fi;
       // if(root==6) cout<<v<<" "<<vis[v]<<endl;
        if(vis[v]){
            int id=query[root][i].se;
            lcaa[id]=find(v);
        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    int t;cin>>t;
    while(t--){
        int n,m;cin>>n>>m;
        for(int i=1;i<=n;i++) e[i].clear();
        for(int i=1;i<=m;i++) query[i].clear();
        me(d,0);me(vis,0);me(q,0);
        for(int i=0; i<n-1; i++){
            int x,y,d;cin>>x>>y;
            d=1;
            e[x].push_back({y,d});
            e[y].push_back({x,d});
        }
        for(int i=1; i<=m; i++){
            int x,y,d;cin>>d>>x>>y;
            query[x].push_back({y,i});
            query[y].push_back({x,i});
            query[d].push_back({y,i+m});
            query[y].push_back({d,i+m});
            ans[i].fi=x,ans[i].se=y;
            q[i]=d;
        }
        //d[1]=1;
        lca(1);
        for(int i=1; i<=m; i++){
            int l=d[ans[i].fi]+d[ans[i].se]-2*d[lcaa[i]];
           // cout<<lcaa[i]<<endl;
            if(d[q[i]]<l+d[ans[i].se]) cout<<"YES"<<endl;
            else if(d[q[i]]==l+d[ans[i].se]){
                if(lcaa[i+m]==1) cout<<"NO"<<endl;
                else cout<<"YES"<<endl;
            }
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}

D不会待补

E
就是问区间l到r的数的next[i]和,next[i]指的是大于等于i的第一个由4或者7组成的数字
发现l和r只有1e9,那么1到1e9之间由4或7组成的数字的个数其实很少
比如长度为1 由2^1个,因为要么是4要么7
那么其实长度到9也就是2^1+2^2+.....+2^9个
但注意一点,极限数据r是1e9 大于等于1e9的第一个是444 444 4444 所以枚举的时候枚举多一点,反正也就1000多个
然后接下来就是求和了

求和的话我是直接在这1000多个满足的数去遍历,
如果num[i]<=r 那么求和就是ans += (num[i]-l+1) * num[i] 然后更新l=num[i]+1否则就是ans +=(r-l+1) * num[i] 其实也就是一块一块的计算而已

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll num[2005],cnt;
ll maxn=5e9;
int main()
{

    queue<ll> q;
    q.push(4),q.push(7);
    while(!q.empty())
    {
        ll now=q.front();
        num[++cnt]=now;
        q.pop();
        if(now*10+4<=maxn&&!mp[now*10+4])
            q.push(now*10+4);
        if(now*10+7<=maxn&&!mp[now*10+7])
            q.push(now*10+7);
    }
   // cout<<cnt<<endl;
    ll l,r;
    cin>>l>>r;
    ll ans=0;
    for(int i=1; i<=cnt; i++)
    {
        if(num[i]>=l)
        {   
            if(num[i]<=r)
            {
                ans+=(num[i]-l+1)*num[i];
                l=num[i]+1;
            }
            else
            {
                ans+=(r-l+1)*num[i];
                break;
            }
        }
    }
    cout<<ans<<endl;

    return 0;
}