CodeForces 938B XOR-pyramid
题外话
当我考试时看到这道题时,离考试结束只剩20分钟了。。。
然后,我飞一般地分析了样例,猜出了结论,过了这道题。(想想都觉得惊心动魄。。。手都要起飞了。。。)
题目
◇题目传送门◆
题目大意
对于一个长度为mm的数组 ,定义函数:
f(b)={ b[1]f(b[1]?b[2],b[2]?b[3],?,b[m?1]?b[m])m=1m>1f(b)={b[1]m=1f(b[1]?b[2],b[2]?b[3],?,b[m?1]?b[m])m>1
现给定一个长度为 nn 序列 ,给出 qq 个询问,对于每个询问,输出给定区间内连续子串的最大函数值。
思路
看题可知, 的值非常地大(q≤100000q≤100000)而nn却非常小( ),很容易往离线操作上靠,即用O(1)O(1)的时间复杂度来回答询问。DP是一个不错的选择。
我们定义f[l][r]f[l][r]为区间[l,r][l,r]中ff函数值。先来找一下规律:
举个例子吧:(根据样例一绘制)
不难发现,
被递归成了f[l+1][r]?f[l][r?1]f[l+1][r]?f[l][r?1]。(画图分析是多么重要)
我们还可以发现边界条件:f[l][r]=a[l](l=r)f[l][r]=a[l](l=r)。
若实在不相信这个结论,就请画出更多的图,你会发现这个结论是正确的。
自然,这道题就变成了一道区间DP题。
我们再定义g[l][r]g[l][r]为区间[l,r][l,r]的最大函数值,可得出状态转移方程:
g[l][r]={
f[l][r]max(f[l][r],g[l+1][r],g[l][r?1])l=rl≠rg[l][r]={f[l][r]l=rmax(f[l][r],g[l+1][r],g[l][r?1])l≠r
所以,还等什么呢?
正解代码
#include<cstdio>
#include<algorithm>
using namespace std;const int Maxn=5000;int N,A[Maxn+5];
int f[Maxn+5][Maxn+5];
int ans[Maxn+5][Maxn+5];int main() {#ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%d",&N);for(int i=1;i<=N;i++) {scanf("%d",&A[i]);ans[i][i]=f[i][i]=A[i];}for(int i=2;i<=N;i++)for(int j=1;j<=N-i+1;j++) {int k=j+i-1;f[j][k]=f[j+1][k]^f[j][k-1];ans[j][k]=max(ans[j+1][k],ans[j][k-1]);if(f[j][k]>ans[j][k])ans[j][k]=f[j][k];}int q;scanf("%d",&q);while(q--) {int l,r;scanf("%d %d",&l,&r);printf("%d\n",ans[l][r]);}return 0;
}