首页 > 技术文章 > Codeforces Global Round 7

liyexin 2020-03-20 23:58 原文

 

     地址:http://codeforces.com/contest/1326

 

 

     题意:给定n,输出一个长度为n的数字,满足以下条件:1:>0  2:各个位上不出现0  3:不能整除自己的任意一位。

     解析:被这题给坑了一下。想不通我的33......7为什么不行,可能太长的话有被7整除的危险,并不能保证万无一失。所以我们需要一个能保证万无一失的通用方法。一个是2333.....3,或是5333.......3。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        if(n==1)
            cout<<"-1"<<endl;
        else
        {
            cout<<"2";
            for(int i=1;i<n;i++)
                cout<<"3";
                cout<<endl;
        }
    }
}

 

 

 

     题意:有点小绕,大致就是我画的这个意思。

 

 

     很明显,题意中有讲,x1=0固定。则a1=b1,直接规定maxx=a1,用这个maxx来维护数组a[]的i-1之前的最大值。ai=bi+maxx,然后更新maxx=max(maxx,bi+maxx);这个顺序不要错。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll b[maxn];
ll a[maxn];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>b[i];
    int x;
    a[1]=b[1];
    ll maxx=a[1];
    for(int i=2;i<=n;i++)
    {
        a[i]=b[i]+maxx;
        maxx=max(maxx,b[i]+maxx);
    }
    for(int i=1;i<=n;i++)
    {
        if(i<n)
            cout<<a[i]<<" ";
        else
            cout<<a[i]<<endl;
    }
}

 

 

 

     题意:也是绕的一批,我这个英语渣压根就没看懂,靠队友才搞懂。

         就是更定一个数量n的数组以及一个k对这个数组进行分块,{|...|,|...|}k是多少,大括号里面就有几个|...|集合,里面是L,R,均为下标。集合之间不能有重叠,要保证全覆盖数组。可以把每个|...|里的最大值提出来,k个最大值相加,得到一个数。目的是找出这个最大数来,以及可以弄出这个数的分块方式有几种。

    解析:既然是k个集合,那么要想保证各个最大值加起来最大,那么就要把前k个大的数做为每个集合里的最大值。以此为基准进行分块操作。再画个图看看:假设k=3

 

 

     三角号表示分界线可放的地方,是不是还是不明白怎么算?没关系,举个例子:有前k大数 a,b。a与b挨着,那么分界线只能插在a上,1种,i+1-i=1,所以根据这个数目就是它们坐标之差。总之就是,记录前k大数的各个坐标之差,乘起来就好了。记得题意里说结果要mod 998244353

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int main()
{
    int n,k;
    cin>>n>>k;
    ll ans=1;
    int idx=-1;
    int x=0;
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        if(x>=n-k+1)
        {
            sum+=x;
            if(idx!=-1)
            {
                ans=(ans*(i-idx))%998244353;
            //    cout<<i-idx<<endl;
            }
            idx=i;
        }
    }
    cout<<sum<<" "<<ans<<endl;
}

 

 

     题意:给你一个字符串,从中找出一个子序列是字符串前缀与字符串后缀(可为空)拼接成的最长回文子字符串。

     解析:首先找前后缀构成的回文:

        while(l<r&&s[l]==s[r])
            l++,r--;

        注意了,这个算出来L是比实际+1,R是比实际-1的。便于下面的找中间最长回文(要它与左前缀相连或者与右后缀相连)。在L-R之间找最长回文,用r2=R,l2=L:分别固定L和R来进行中间r2,l2的滑动寻找回文串:

 

 

      PS:substr(l,d)返回的是以l下标为开头,长度为d的字符串。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int check(string &s,int l,int r)
{
    while(l<=r&&s[l]==s[r])
    {
        l++;
        r--;
    }
    return r<l?1:0;  //如果r<l了,肯定是回文串了,返回1,否则返回0
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        cin>>s;
        int len=s.length();
        int l=0,r=len-1;
        while(l<r&&s[l]==s[r])
            l++,r--;
        int l2,r2;
        for(r2=r;r2>=l;r2--)
        {
            if(check(s,l,r2))
            {
                break;
            }
        }
        for(l2=l;l2<=r;l2++)
        {
            if(check(s,l2,r))
                break;
        }
//        cout<<l2<<" "<<r2<<endl;
        cout<<s.substr(0,l);    //L算出来比实际+1的,长度即为L-1-0+1=L;
        if((r2-l)>(r-l2))
            cout<<s.substr(l,r2-l+1);
        else
            cout<<s.substr(l2,r-l2+1);
        cout<<s.substr(r+1)<<endl;//R算出来是比实际-1的,直接是输出r+1到串尾
    }
}

 

推荐阅读