2019 ACM训练计划——( 每天5题 ) 训练计划 11

A

最长回文


题目大意

就是将两个字符串A和B选择子串进行拼接,然后求通过这样的方法能得到的最长回文串的长度


题解

对字符串A和字符串B各自进行一次manacher,求出p数组
然后枚举回文中心,我们在pA[i]和pB[i]取一个max,表示我们暂时先只取两个串中较长的回文串,然后对于这个回文串,我们可以向两边拓展,因为假设A的回文串的左边的字符不在A的回文串中,但是可以和B右边的字符相同的话,就可以形成回文,边枚举边拓展取最大值即可得到A串和B串取出一段来形成回文串的最大值

#include
using namespace std;
const int maxn=1e5+5;
int n,len;
char s[maxn],a_new[maxn*2],b_new[maxn*2];
int lena[maxn*2],lenb[maxn*2];

void init(char *s_new){
    cin>>s;
    int j=1;
    s_new[0]='$';
    s_new[1]='#';
    for(int i=0;i<n;i++){
        s_new[++j]=s[i];
        s_new[++j]='#';
    }
    s_new[++j]='\0';
}
void Manacher(char *s_new,int *p){
    int id=1,mx=0;
    for(int i=1;i<=len;i++){
        if(i<mx) p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(s_new[i+p[i]]==s_new[i-p[i]]) p[i]++;
        if(i+p[i]>mx){
            id=i;
            mx=i+p[i];
        }
    }
}
int query(){
    int ans=1;
    for(int i=2;i<=len;i++){
        int tmp=max(lena[i],lenb[i-2]);
        while(a_new[i-tmp]==b_new[i+tmp-2]) tmp++;
        ans=max(ans,tmp);
    }
    return ans-1;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n){
        init(a_new);
        init(b_new);
        len=2*n+1;
        Manacher(a_new,lena);
        Manacher(b_new,lenb);
        int ans=query();
        cout<<ans<<endl;
    }
    return 0;
}

B

回文串


题目大意

最长回文子串长度Manacher模板


题解

注意我的模板代码里面n代表起初输入的字符串的长度

len代表的是经过变化后的字符串的长度

#include
using namespace std;
const int maxn=1e5+5;
int n,len;
char s[maxn],a_new[maxn*2];
int lena[maxn*2];

void init(char *s_new){
    int j=1;
    s_new[0]='$';
    s_new[1]='#';
    for(int i=0;i<n;i++){
        s_new[++j]=s[i];
        s_new[++j]='#';
    }
    s_new[++j]='\0';
}
int Manacher(char *s_new,int *p){
    int id=1,mx=0;
    int ans=1;
    for(int i=1;i<len;i++){
        if(i<mx) p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(s_new[i+p[i]]==s_new[i-p[i]]) p[i]++;
        if(i+p[i]>mx){
            id=i;
            mx=i+p[i];
        }
        ans=max(ans,p[i]-1);
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>s){
        n=strlen(s);
        init(a_new);
        len=strlen(a_new);
        cout<<Manacher(a_new,lena)<<endl;
    }
    return 0;
}

C

Codeforces Round #260 (Div. 1), problem: (A) Boredom


题目大意

dp,由题意推递推公式


题解

做法是先存下每个数的个数放在c中,消除一个数i,会获得 c[ i ] * i 的值(因为可以消除c[i]次),如果从0的位置开始向右消去,那么,消除数i时,i-1可能选择了消除,也可能没有

如果消除了i-1,那么i值就已经不存在,dp[i] = dp[i-1],如果没有被消除,那么dp[i] = dp[i-2]+ c[i]*i。
在上面两者中取最大值即可。

#include
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll a[maxn],dp[maxn];;
int n;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n){
        for(int i=1;i<=n;i++){
            ll x;
            cin>>x;
            a[x]++;
        }
        dp[1]=a[1];
        for(int i=2;i<=maxn;i++){
            dp[i]=max(dp[i-1],dp[i-2]+a[i]*i);
        }
        cout<<dp[maxn]<<endl;
    }
    return 0;
}

D

Codeforces Round #280 (Div. 2), problem: (B) Vanya and Lanterns


题目大意

求让路灯覆盖整个路的最小半径


题解

我们要考虑三个点,首先是起点附近的第一个路灯,其次是终点附近的第一个路灯,它们两个距离要取最大值 然后就是其他路灯,其它路灯的覆盖范围是它们位置之差的一半,要想覆盖整个路的话,需要从这三者当中求得一个最大值

#include
using namespace std;
int n,m;
typedef long long ll;
const int maxn=1e3+10;
ll a[maxn];
int main(){
    while(cin>>n>>m){
        for(int i=0;i<n;i++)
            cin>>a[i];
        sort(a,a+n);
        double ans=max(a[0]-0,m-a[n-1]);
        for(int i=1;i<n;i++)
            ans=max(ans,(a[i]-a[i-1])/2.0);
        printf("%.10f\n",ans);
    }
    return 0;
}

E

Codeforces Round #119 (Div. 2), problem: (A) Cut Ribbon


题目大意

给出一条丝带长度n,要求把丝带切成给定长度a、b、c中的一种或多种,问:最多能切成几条?(保证至少有一个解)


题解

按照题意就很明确是一个完全背包的题目,要将背包装满,然后又要最大化丝带个数(即最大价值)

#include
using namespace std;
const int maxn=1e4+10;
int a[maxn],dp[maxn];
int n;
const int INF=0x3f3f3f3f;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>a[0]>>a[1]>>a[2];
    for(int i=1;i<=n;i++)
        dp[i]=-INF;
    dp[0]=0;
    for(int i=0;i<=2;i++){
        for(int j=a[i];j<=n;j++){
            dp[j]=max(dp[j],dp[j-a[i]]+1);
        }
    }
    cout<<dp[n]<<endl;
    return 0;
}

另外附上完全背包,01背包,多重背包模板代码写的

#include
using namespace std;
const int maxn=1e4+10;
int a[maxn],dp[maxn],c[maxn];
int n;
const int INF=0x3f3f3f3f;
void CompletePack(int v,int w,int m)
{
    for(int j=v; j<=m; j++)
        dp[j] = max(dp[j],dp[j-v]+w);
}
void ZeroOnePack(int v,int w,int m)
{
    for(int j=m; j>=v; j--)
        dp[j] = max(dp[j],dp[j-v]+w);
}
void MultiPack(int v,int w,int m,int c)
{
    if(v*c > m) CompletePack(v,w,m);
    else
    {
        int k = 1;
        while(k < c)
        {
            ZeroOnePack(k*v,k*w,m);
            c -= k;
            k *= 2;
        }
        ZeroOnePack(c*v,c*w,m);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>a[0]>>a[1]>>a[2];
    for(int i=0;i<n;i++)
        dp[i]=-INF;
    dp[0]=0;
    for(int i=0;i<3;i++)
        CompletePack(a[i],1,n);
    cout<<dp[n]<<endl;
    return 0;
}
学如逆水行舟,不进则退

你可能感兴趣的:(Codeforces✍,2019,ACM训练计划,(,每天5题,),训练计划,11)