• Educational Codeforces Round 60 (Rated for Div. 2) 题解


    Educational Codeforces Round 60 (Rated for Div. 2)

    题目链接https://codeforces.com/contest/1117

    A. Best Subsegment

    题意:

    给出n个数,选取一段区间[l,r],满足(al+...+ar)/(r-l+1)最大,这里l<=r,并且满足区间长度尽可能大。

    题解:

    因为l可以等于r,所以我们可以直接考虑最大值,因为题目要求,直接求连续的最大值的长度就是了。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    int n;
    int a[N];
    int main(){
        cin>>n;
        int cnt=1,ans=1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int mx=*max_element(a+1,a+n+1);
        for(int i=2;i<=n;i++){
            if(a[i]==mx && a[i-1]==mx){
                cnt++;
            }else{
                ans=max(ans,cnt);
                cnt=1;
            }
        }
        cout<<max(ans,cnt);
        return 0;
    }
    View Code

    B. Emotes

    题意:

    输入n,m,k,n表示元素个数,每个元素都有其权值;m表示最多可以选取的个数;k表示同一个元素最多被连续选取多少次。

    这里每种元素都有无限多个,问怎样选可以使得最终获得权值和最大。

    题解:

    这个直接贪心就好了。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    ll n,m,k;
    ll a[N];
    int main(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
        }
        sort(a+1,a+n+1);
        reverse(a+1,a+n+1);
        ll fir = a[1],sec = a[2];
        ll ans=0;
        if(fir==sec){
            cout<<m*fir;
        }else{
            ans = k*fir+sec;
            ll tmp = m/(k+1);
            ans*=tmp;
            tmp*=(k+1);
            ans+=(m-tmp)*fir;
            cout<<ans;
        }
        return 0;
    }
    View Code

    C. Magic Ship

    题意:

    在二维坐标轴上给出起点和终点的坐标,然后会给n天的天气预报,表示风向,不同的风向对应那一天会多往哪个方向走。天气情况是循环来的 ,循环节为n。

    现在问最少要多少天,可以让船从起点走到终点。如果无论如何走不到终点,输出-1。

    题解:

    这个题我一开始考虑复杂了。其实这里风向带来的位置变化,和船开动的位置变化,可以分开来,也就是说,如果考虑n天的位置变化,可以先看风向给船带来的影响(船会被吹到哪去),再考虑船自身的航行方向。如果想清楚了这一点,那么直接二分天数就好了,最后通过曼哈顿距离来判断可行性。

    这里单调性的证明也有点意思,很显然地,时间越短越不可能到终点;另一个方面,假设船在x时间可以到终点,那么时间越长,也更有可能到终点,因为船可以借助风向,在一个位置保持不变。

    细节见代码吧(注意二分天数):

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+5;
    struct Point{
        ll x,y;
    }st,ed,cur;
    char s[N];
    int n;
    ll prex[N],prey[N];
    int check(ll x){
        ll d = x/n;
        cur.x=st.x+d*prex[n];
        cur.y=st.y+d*prey[n];
        cur.x=cur.x+prex[x%n];
        cur.y=cur.y+prey[x%n];
        ll dis=abs(cur.x-ed.x)+abs(cur.y-ed.y);
        return dis<=x;
    }
    int main(){
        cin>>st.x>>st.y>>ed.x>>ed.y;
        cin>>n;
        scanf("%s",s+1);
        for(int i=1;i<=n;i++){
            prex[i]=prex[i-1];prey[i]=prey[i-1];
            prex[i]+=(s[i]=='R');
            prex[i]-=(s[i]=='L');
            prey[i]+=(s[i]=='U');
            prey[i]-=(s[i]=='D');
        }
        ll l=0,r=1e15,mid;
        while(l<r){
            mid=l+r>>1;
            if(check(mid)) r=mid;
            else l=mid+1;
        }
        if(l==1e15) cout<<-1;
        else cout<<l;
        return 0;
    }
    View Code

    D. Magic Gems

    题意:

    给出n和m,然后有n个可分解物品,连续的m个可分解物品可以被分解成m个不可分解物品。现在问一共有多少种分解方式,可以让最后都有n个物品(包含可分解与不可分解)。

    题解:

    这题可以考虑组合数来求解,枚举分解i组物品,那么答案就是C(n-i*(m-1),i),但是这个题行不通,枚举i就爆掉了。

    通过考虑第i个数的状态,可以考虑递推:设fi为前i个物品的分解总数,那么fi=fi-1+fi-m,分别对应第i个物品不参与分解以及参与分解。

    结合题目数据范围,要用矩阵乘法来加速,具体矩阵构造什么的看代码吧:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 105,MOD = 1e9+7;
    struct matrix{
        ll A[N][N];
        int n,m;
        matrix(){
            memset(A,0,sizeof(A));
        }
        void Print(){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    cout<<A[i][j]<<" ";
                }
                cout<<endl;
            }
        }
    };
    matrix operator * (const matrix &a,const matrix &b){
        matrix ans;
        ans.n=a.n;ans.m=b.m;
        for(int i=1;i<=ans.n;i++){
            for(int j=1;j<=ans.m;j++){
                for(int k=1;k<=b.n;k++){
                    ans.A[i][j]=(ans.A[i][j]+a.A[i][k]*b.A[k][j]%MOD)%MOD;
                }
            }
        }
        return ans ;
    }
    matrix operator + (const matrix &a,const matrix &b){
        matrix ans;
        ans.n=a.n;ans.m=a.m;
        for(int i=1;i<=ans.n;i++){
            for(int j=1;j<=ans.m;j++){
                ans.A[i][j]=(a.A[i][j]+b.A[i][j])%MOD;
            }
        }
        return ans ;
    }
    matrix qp_Mat(matrix a,ll b){
        matrix ans;
        ans.n=ans.m=a.n;
        for(int i=1;i<=ans.n;i++) ans.A[i][i]=1;
        while(b){
            if(b&1) ans=ans*a;
            a=a*a;
            b>>=1;
        }
        return ans ;
    }
    int main(){
        ll n,m;
        cin>>n>>m;
        matrix trans;
        trans.n=m;trans.m=m;
        trans.A[1][1]=trans.A[1][m]=1;
        for(int i=2;i<=m;i++) trans.A[i][i-1]=1;
        matrix ans;
        ans.n=m;ans.m=m;
        for(int i=1;i<=m;i++) ans.A[i][1]=1;
        if(n<m){
            cout<<1;
        }else{
            matrix Ans = qp_Mat(trans,n-m+1);
            Ans=Ans*ans;
            cout<<Ans.A[1][1];
        }
        return 0;
    }
    View Code

    E. Decypher the String

    题意:

    每组数据会有n个交换操作,但是这是个交互题不会告诉你。他只会告诉你f(长度为n的串),表示将串进行n次交换操作过后得到的串。

    然后你只有三次询问机会,最后输出原串是什么。

    题解:

    这是一个很有意思的交互题。n最大只有10000,通过观察26^2<n<26^3,那么可以往26这方面考虑一下。

    注意到当n<=26时,我们只需要一个所有26个字母的顺序排列,就很容易知道位置的变化情况。

    然后构造这样的字符串:aaa...aaa(26*26)bbb....,并且称26*26为一个大段,那么类比上面的情况,通过询问,很容易知道目前第i个位置在原来哪个大段。

    然后构造:aaa..aa(26)bbb...bb...zz....,上面每个大段中有26*26个数,也就是我们将每个数的范围限定在了某个长度为26*26的区间中,现在我们构造的字符串,可以进一步将第i个数范围缩小到长度为26的区间。

    最后再构造ab..zabc...这样的串,就可以找到第i个数原来的位置在哪里了。

    这三个操作的本质其实就是求a*262+b*261+c中,每个位置i对应的a,b,c值,这里的a,b,c都是不超过25的。

    是不是感觉十分巧妙...将问题转化为26进制的问题,据说还可以通过crt来搞,但目前我的姿势水平还不够呜呜。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    int n;
    char str[N],s[N],ans[N];
    ll f[N];
    int main(){
        scanf("%s",str);
        int len=strlen(str);
        for(int i=0;i<3;i++){
            for(int j=0;j<len;j++){
                if(i==0) s[j]='a'+j%26;
                if(i==1) s[j]='a'+j/26%26;
                if(i==2) s[j]='a'+j/26/26%26;
            }
            printf("? %s
    ",s);
            fflush(stdout);
            char tmp[N];
            scanf("%s",tmp);
            for(int j=0;j<len;j++){
                if(i==0) f[j]+=tmp[j]-'a';
                if(i==1) f[j]+=(tmp[j]-'a')*26;
                if(i==2) f[j]+=(tmp[j]-'a')*26*26;
            }
        }
        char ans[N];
        for(int i=0;i<len;i++){
            ans[f[i]]=str[i];
        }
        printf("! ");
        printf("%s",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
    【BZOJ1030】[JSOI2007]文本生成器 AC自动机+动态规划
    【BZOJ3943】[Usaco2015 Feb]SuperBull 最大生成树
    【BZOJ3940】【BZOJ3942】[Usaco2015 Feb]Censoring AC自动机/KMP/hash+栈
    【BZOJ3172】[Tjoi2013]单词 AC自动机
    【HDU2896】病毒侵袭 AC自动机
    【HDU2222】Keywords Search AC自动机
    【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP
    结婚晚了
    无毒食品
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10409018.html
Copyright © 2020-2023  润新知