2018.6.6 周中练习2

50 篇文章 0 订阅

本场比赛A了三个题。。B题卡了很长时间,导致C题会做但是没有时间敲,比赛结束10分钟后A了C。

先做的A题,XOR-pyramid 

题意:

数组b的f运算是

f(b1,b2,b3,,,bn)=f(b1^b2,b2^b3,,,b(n-1)^bn);

当n==1时,f(b1)=b1;

给定数组b,q组询问,求[l,r]区间子区间的f运算结果的最大值

思路:

画个形成图,发现规律,然后由于n的的数据量比较小,所以可以预处理一下所有的区间的f运算值,然后再循环一遍存一下最大值.

dp[i][j]表示区间[i,i+j-1]的f运算结果,ans[i][j]表示区间[i,i+j-1]的所有子区间的f运算的最大值

代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 7901
long long dp[5005][5005],ans[5005][5005],n,p,a[5005],l,r;
int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        dp[i][1]=a[i];
        ans[i][1]=a[i];
    }
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j+i-1<=n;j++)
        {
            dp[j][i]=(dp[j][i-1]^dp[j+1][i-1]);
            //cout<<i<<" "<<j<<" "<<dp[j][i-1]<<" "<<dp[j+1][i-1]<<" "<<dp[j][i]<<endl;
        }
    }
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j+i-1<=n;j++)
        {
            ans[j][i]=max(ans[j][i-1],ans[j+1][i-1]);
            ans[j][i]=max(ans[j][i],dp[j][i]);
        }
    }
    scanf("%lld",&p);
    while(p--)
    {
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",ans[l][r-l+1]);
    }
}

然后一直在做B题。。。

题意:给定一个n长度的01字符串,求0的个数==1的个数的 连续区间最大长度

思路:明显的区间dp,但是还要加优化,不然TLE,然后加了思维优化:存一下0的所有位置,假设最长区间内有i个0i个1,区间内最后一个0是第j个0,那么当且仅当,第j个0和第j-i+1个0 之间的区间长度<=i+i,并且第j+1个0和第j-i个0的区间长度>=i+i;

但是比赛结束后听大家讨论,大多是用前缀和的区间dp做的

感想:

这个题,加了思维优化后,因为一个1---第j+1个0的区间没有i个0或者没有i给1了就可以break了,没有+1,错了一直没有找出来。。。浪费了太多时间。。。最后好不容易一步一步的尝试输出试出来错误的地方。。。结果最后发现根本没必要加那个break。。。。也能A。。。最终导致wa+11。。。。。

代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 7901
int l,r,n,ans,ok,a,b,dp[5][100050],x,y,j,z,w[100050];
char s[100050];
int main()
{
    scanf("%d",&n);
    scanf("%s",s);
    ok=0;
    ans=0;
    a=0;b=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i-1]=='0') {a++;
        w[a]=i;
        dp[0][i]=dp[0][i-1]+1;dp[1][i]=dp[1][i-1];}
        else {b++;dp[1][i]=dp[1][i-1]+1;dp[0][i]=dp[0][i-1];}
    }
    w[a+1]=n+1;
    x=min(a,b);
    for(int i=x;i>=1;i--)
    {
        y=i*2;
        for(j=a;j>=i;j--)
        {
           // z=w[j+1]-1;就是这个j忘了+1!!!!可以删掉!!
           // if(dp[0][z]<i||dp[1][z]<i) break;
            //cout<<i<<" "<<j<<endl;
            if(w[j+1]-w[j-i]-1>=y&&w[j]-w[j-i+1]+1<=y)
            {
                ans=y;
                ok=1;
                break;
            }
        }
        if(ok) break;
    }
    printf("%d\n",ans);
}

然后是看很多人A了E

题意:给定一个字符串,每个字符x可以变成x+1,可以变多次。。

求,变完后,能不能有子列列“abcdefghijklmnopqrstuvwxyz”输出变完后的字符串

不能完成输出-1

思路:

这个题可以算是本次最简单的题了,但是题意没怎么读明白,。。。没读清,是只能变一次,还是可以重复变多次,再就是输出的字符串变后的,一开始以为是输出“abcdefghijklmnopqrstuvwxyz”。。。然后猜题意wa+4.。。

代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 7901
int l,num;
char s[100050],x;
string ans;
int main()
{
    scanf("%s",s);
    int i=0,l=strlen(s);
    x='a';
    while(i<l)
    {
        if(s[i]<=x&&x<='z') {ans+=x;x++;}
        else  ans+=s[i];
        //cout<<i<<" "<<ans<<endl;
        i++;
    }
    if(x>'z') cout<<ans<<endl;
    else printf("-1\n");
}

最后做的C,但是昨晚的时候已经比赛结束了。。

就是求最长递增子序列的长度,要求子序列任意两数不互质、

思路:像是一个lis的dp题,但是感觉自己没想到怎么处理点的更新,,然后就做成了思维题。。

就是给每个数找最大长度,找的是因子的最大长度,然后将所有的因子,都更新成这个最大长度

依据就是两个数不互质,一定有一个非一的共同因子,,,那么数的高度,就可以变成因子的高度,保留因子的最大高度,继续往下更新就好了。。

代码:

 
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 7901
int l,num,dp[100005],n,a[100005],ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        num=1;
        for(int j=2;j<=sqrt(a[i]);j++)
        {
            if(a[i]%j==0) {dp[j]++;
            num=max(num,dp[j]);
            if(j*j!=a[i])
            {
                dp[a[i]/j]++;
            num=max(num,dp[a[i]/j]);}
            }

            //cout<<i<<" "<<j<<" "<<num<<endl;
        }
        for(int j=2;j<=sqrt(a[i]);j++)
        {
            if(a[i]%j==0)
            {
                dp[j]=num;
                dp[a[i]/j]=num;
            }
        }
        dp[a[i]]=num;
        ans=max(ans,dp[a[i]]);
    }
    printf("%d\n",ans);

}
/*
6
2 4 6 9 12 15
*/




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值