zoukankan      html  css  js  c++  java
  • CF811C Solution

    题目链接

    题解

    dp题呐,需要预处理出\(sum,lst,fst\)数组,\(sum[l][r]\)表示区间\([l,r]\)依题意的异或值,\(lst[i]\)表示\(a\)数组中值为\(i\)的元素最后一次出现的下标,\(fst[i]\)表示\(a\)数组中值为\(i\)的元素第一次出现的下标。

    状态:\(dp[i]\)表示\([a_1,a_i]\)的异或最大和。

    转移:找到每一个可以划为车厢的区间\([l,r]\)\(dp[r]=max(dp[r],dp[l-1]+sum[l][r])\)

    至于寻找车厢区间,车厢区间需要满足其中所有元素\(lst[a_j]\le r\)\(fst[a_j]\ge l\)。由\(r\)\(1\)倒序遍历\(a\)数组,如果出现\(lst[a_j]>r\)则退出循环,如果当前全部\(fst[a_k]\ge j\)\(fst\)最小值\(\ge j\))则更新\(dp\)值。

    目标状态:\(dp[n]\)

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5010;
    int a[N],dp[N],sum[N][N],lst[N],fst[N];
    bool qwq[N];//qwq[i]:当前循环中值为i的元素是/否(1/0)出现过
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=n;i++)
    	{
    		memset(qwq,0,sizeof(qwq));
    		sum[i][i]=a[i]; qwq[a[i]]=1;
    		for(int j=i+1;j<=n;j++) 
    		{
    			if(!qwq[a[j]]) sum[i][j]=a[j]^sum[i][j-1];//第一次出现
    			else sum[i][j]=sum[i][j-1];
    			qwq[a[j]]=1;
    		}
    		lst[a[i]]=i;
    		if(!fst[a[i]]) fst[a[i]]=i; 
    	}
    	for(int i=1;i<=n;i++)
    	{
    		int s=fst[a[i]];//s:当前循环中fst[j]最小值
    		for(int j=i;j>=1;j--)
    		{
    			if(lst[a[j]]>i) break;
    			s=min(s,fst[a[j]]);
    			if(j==s) dp[i]=max(dp[i],dp[j-1]+sum[j][i]);//易得s>=j
    		}
    		dp[i]=max(dp[i],dp[i-1]);
    	}
    	printf("%d",dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    汉罗塔问题
    有进度条圆周率计算
    turtle库笔记
    OwnCloud建立属于自己私有的云存储网盘
    HTTP 常见请求状态码
    虚拟机部署Kubernetes集群
    常用文件头(16进制)
    配置LAMP环境
    Linux系统日志
    Java的socket通信与操作系统的SocketAPI关系探究
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14501898.html
Copyright © 2011-2022 走看看