zoukankan      html  css  js  c++  java
  • HDU 4455 Substrings(线性dp,很有意思)

    题意:这个题给你n个数,然后有q组询问,无修改,每次询问一个长度x,问你所有长度为x的区间价值加和是多少,区间的价值的计算是这样定义的,一个区间的价值就等于这个区间中不同数字的个数

    思路:看了题解虽然理解了,但感觉还是很难想啊,原本这个题卡在了怎么把n2的降维成n的,这个题目也算是很经典的一个套路吧,疯狂预处理,把所需要的信息不断转化,疯狂降维预处理,然后达到On递推,感觉对于dp[i]和dp[i-1]之间的关系,单点贡献的那一部分不怎么容易想到,而且想到了单点贡献,也想不到怎么预处理,QAQ

    传送门一只

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int maxn=1e6+7;
    int n;
    int a[maxn],cnt[maxn];
    LL dp[maxn],vis[maxn];
    int main()
    {
        while(~scanf("%d",&n),n){
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            int res=0;
            memset(dp,0,sizeof(dp));
            for(int i=n;i>=1;i--){
                if(!dp[a[i]])dp[a[i]]=1,res++;
                cnt[n-i+1]=res;
            }
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=n;i++){
                dp[i]=vis[a[i]];
                vis[a[i]]=i;
            }
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=n;i++){
                vis[i-dp[i]]++;
            }
            vis[n+1]=0;
            for(int i=n;i>=1;i--)vis[i]+=vis[i+1];
            dp[1]=n;
            for(int i=2;i<=n;i++){
                dp[i]=dp[i-1]-cnt[i-1]+vis[i];
            }
            int q;
            scanf("%d",&q);
            while(q--){
                int x;
                scanf("%d",&x);
                printf("%lld
    ",dp[x]);
            }
        }
        return 0;
    }
  • 相关阅读:
    字符串序列处理
    51nod1065 最小正子段和
    51nod1043 幸运号码
    51nod1035 最长的循环节
    51nod 1021 石子归并
    POJ 2387 Til the Cows Come Home
    第一次博客作业
    Python命令行参数以及文件读入写出
    团队介绍及选题报告
    结对编程作业
  • 原文地址:https://www.cnblogs.com/lalalatianlalu/p/9981507.html
Copyright © 2011-2022 走看看