xjoi contest1(cf1084原题)

学军奋斗组训练contest1

T1:The Fair Nut and Elevator

这题说实在的还是折腾了我不少时间,因为本蒟蒻可怜的英语能力。

题意:

有N(n <= 100)个楼层,每层楼里住着ai 个人,其中有一台奇怪的电梯管理着这栋楼上上下下。它固定停在某一层(由你决定),当有人要使用时依次到达起点和终点最后回来(每个人只会从一楼到自己的,或者从自己的到1层,每天上下班共一个来回),才会进行下一轮工作,且同时只会运输一个人。(真省电。。。。。。)为了省电,于是想问你当电梯停在任意楼层时,最少需要跑多少楼层。

思路的话,直接暴力枚举电梯固定停的楼层,在再计算,n2无压力水过。

Select Code
#include<bits/stdc++.h>
using namespace std;
int a[101];
int main()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        int x;
        scanf("%d",&x);
        a[i] = x;
    }
    int ans = 1000000001;
    for(int i = 1;i <= n;i++)
    {
        int sum = 0;
        for(int j = 1;j <= n;j++)
        {
            sum += 2*a[j]*(abs(j-i)+j-1+i-1);
        }
        ans = min(ans,sum);
    }
    cout << ans; 
    return 0;
}

T2:Kvass and the Fair Nut

 很水的二分题,但是我考试时打挂了。没办法,只能糊式子。

题意:

有n(n <= 103)杯水,其中第i杯水有ai(a<= 109)份水,你先在需要从这些杯子中倒出总共s(s <= 1012)份的水,使含有最少水的杯子含水最多。求这个值。

其实这个式子也很好糊,考虑一下一个贪心思路,就是尽可能使所有的杯子里含的水更接近。于是我们先算出来操作结束后的总水量,然后除以杯子的数量,但是要注意,答案不能小于初始最小水量。

#include<bits/stdc++.h>
using namespace std;
long long a[10001];//记得一定要long long 不然会挂
long long n,s;
int main()
{
    cin >> n >> s;
    long long mx = 0;
    long long sum = 0;
    long long mn = 1000000000000;
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld",&a[i]);
        mn = min(a[i],mn); 
        sum += a[i];
    }
    if(sum < s) 
    {
        puts("-1");
        return 0;
    }
    cout << min(mn,(sum-s)/n); 
    return 0;
}

T3:The Fair Nut and String

一道典型的结论+字符串题,题目还是比较新颖的。

题意:

有一字符串(s.length <= 105),现在你需要求出所有满足条件的location(地址)的子序列。

它需要满足以下条件:
  1、所有location对应字符都是‘a’;
  2、所有location之间都至少有一个location对应‘b’;

考虑当你遇到一个b的时候,那么所有在这个b之前就可以满足的子序列都可以加上这个b后面所有出现的a中的一个匹配。

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
char s[100001];
int main()
{
    scanf("%s",s+1);
    int len = strlen(s+1);
    long long ans = 1,cnt = 1;
    for(int i = 1;i <= len;i++)
    {
        if(s[i] == 'a') 
            cnt++;
        else if(s[i] == 'b')
        {
            ans = (ans*cnt)%mod;
            cnt = 1;
        }
    }
    ans = (ans*cnt) % mod;
    cout << ans-1 << endl;
    return 0;

}

 T4:The Fair Nut and the Best Path

一道简单的树型DP题,只要想到了应该还是挺好写的。

题意:

有一棵有n (n <=  3*105)个点的树,其中所有的边都是负权的,点是正权的。要求一个权值最大的简单路径。

考虑树上任意一条简单路径必定是从一个点一直向子树延伸下去。假设任意一个点为始祖的路径,使简单路劲权值最大,那么一定是有最大和次大的两条子链和当前祖先形成的。这个子链大小可以用最大的子链DP直接转移,但是注意如果子链为负,那么不转移,直接使用该点的权值。

#include<bits/stdc++.h>
using namespace std;
int val[300005];
long long f[300005],dp[300005];
vector <pair <int, int> > vec[300005];
int n;
long long ans = 0;
void dfs(int u,int fa)
{
    f[u] = val[u];
    dp[u] = val[u];
    long long mx = 0,Mx = 0;
    for(int i = 0;i < vec[u].size();i++)
    {
        if(vec[u][i].first == fa) continue;
        dfs(vec[u][i].first,u);
        if(mx < f[vec[u][i].first] - vec[u][i].second)
        {
            Mx = mx;
            mx = f[vec[u][i].first] - vec[u][i].second;
        }
        else if(Mx < f[vec[u][i].first] - vec[u][i].second)
        {
            Mx = f[vec[u][i].first] - vec[u][i].second;
        }
    }
    dp[u] += mx;
    dp[u] += Mx;
    f[u] += mx;
    ans = max(max(ans,dp[u]),f[u]);
}
int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&val[i]);
    }
    int u,v,w;
    for(int i = 1;i < n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        vec[u].push_back(make_pair(v,w));
        vec[v].push_back(make_pair(u,w));
    }
    dfs(1,-1);
    cout << ans << endl;
    return 0;
}

T5:The Fair Nut and Strings

这题好多同机房(当然是最差的机房,我这么菜)的人都卡在这。但是我好想没什么压力就糊出了结论水过了。

有两个长度为n(n <= 5*105)的“ab”字符串,其中的k个最多有多少前缀和。

这题其实仔细思考一下只要二进制按位相减就好了。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n,k;
    cin >> n >> k;
    string s,t;
    cin >> s >> t;
    long long ans = 0;
    long long suma = 0,sumb = 0;
    for(int i = 0;i < n;i++)
    {
        long long now;
        suma *= 2;
        sumb *= 2;
        if(s[i] == 'b') 
            suma++;
        if(t[i] == 'b') 
            sumb++;
        now = sumb - suma + 1;
        if(now >= k)
        {
            ans += (n-i)*k;
            break ;
        }
        ans+=now;
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/mzyy1001/p/10145496.html