本场比赛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
*/