• 1485F. Copy or Prefix Sum(DP+懒惰标记)


    给出一个数组(b)

    (b_i)可以等于(a_i),也可以等于(sum_{j=1}^ia_j)

    询问有多少个数组(a)

    对每个位置(i),你可以选择(a_i=b_i)(a_i=b_i-sum_{k=1}^{i-1}a_k)

    如果(sum_{k=1}^{i-1}a_k=0),那么这两种选择构成的数组是一样的,对答案的贡献是1。

    一种(O(n^2logn))的做法:

    定义(f(i,j))是当前在第(i)位,前缀和是(j)的情况有多少种。

    状态转移方程:

    如果你选择(b_i=a_i),同时(j eq 0)

    (f(i+1,j+b_i)=f(i,j))

    如果你选择(b_i=sum_{k=1}^ia_k)

    (f(i+1,b_i)=f(i,j))

    (Map)实现状态转移方程可以把时间复杂度控制在(O(n^2logn))

    观察状态转移方程,就是把当前位置的所有(j eq 0)(f(i,j))变成(f(i+1,j+b_i)),同时把所有(f(i,j))加给(f(i+1,b_i))

    第二步就是当前的情况数,第一步就是当前的情况数减去(j=0)的情况数。

    合并就是:下一步的情况数=当前的情况数*2-(j=0)的情况数。

    怎么快速计算(j=0)的情况数:

    考虑到每一步,所有状态统一加(b_i),那么第二步可以转化为把所有的(f(i,j))加给(f(i+1,0)),然后把两步的所有情况都变成(f(i+1,j+b_i))

    维护一个懒惰标记,标记当前一共加了多少(即(b)的前缀和)。可以直接用(lazy)表示。

    然后转移的时候,(f(lazy))就表示当前(j=0)的情况,每次转移把(lazy)(b_i)即可。

    时间复杂度(O(nlogn))

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    const int mod=1e9+7;
    int b[maxn],n,t;
    map<long long,long long> f;
    int main () {
    	scanf("%d",&t);
    	while (t--) {
    		scanf("%d",&n);
    		for (int i=1;i<=n;i++) scanf("%d",b+i);
    		f.clear();
    		long long lazy=0;
    		long long ans=1;
    		f[0]=1; 
    		for (int i=1;i<=n;i++) {
    			long long tt=ans;
    			ans=(ans*2-f[lazy]+mod)%mod;
    			f[lazy]=tt%mod;
    			lazy-=b[i];
    		}
    		ans%=mod;
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    Oracle 推出 ODAC for Entity Framework 和 LINQ to Entities Beta版
    Entity Framework Feature CTP 5系列文章
    MonoDroid相关资源
    MSDN杂志上的Windows Phone相关文章
    微软学Android Market推出 Web Windows Phone Marketplace
    使用 Visual Studio Agent 2010 进行负载压力测试的安装指南
    MonoMac 1.0正式发布
    Shawn Wildermuth的《Architecting WP7 》系列文章
    使用.NET Mobile API即51Degrees.mobi检测UserAgent
    MongoDB 客户端 MongoVue
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14400180.html
Copyright © 2020-2023  润新知