• 神在夏至祭降下了神谕 题解


      先说一句题外话,有谁看到的第一眼看成了某站的知名up主夏日祭?

    题面

    夏至祭是一场迎接祖灵于夏季归来同时祈求丰收的庆典。村里的男人会在广
    场上演出冬之军跟夏之军的战争,夏之军会打倒冬之军的大将冬男,再放火将他
    连山车一起烧掉。
    谢尔吉斯村长已经选好了N个人参加演出,其中一些人负责演夏之军,另一
    些人负责演冬之军。由于人数众多,谢尔吉斯想把这N个人分成若干个连续的
    段。为了保证演出的顺利进行,每段的夏之军人数与冬之军人数之差的绝对值不
    能超过K。
    谢尔吉斯想知道符合条件的划分方案有多少种。由于符合条件的方案有很多,
    你只要输出方案数除以1e9+7的余数。
    【输入格式】
    第一行两个整数N,K,意义如题目描述所示。 接下来一行N个整数,第i个整数为0表示第i个人是夏之军,1表示第i个
    人是冬之军。
    【输出格式】
    一行一个整数,表示符合条件的方案数除以1e9+7的余数。
    【样例输入】
    4 1
    0 0 1 1
    【样例输出】
    5
    【样例说明】
    合法的5种方案分别为:
    0 0 1 1
    0 0 1|1
    0|0 1 1
    0|0 1|1
    0|0|1|1
    而00|1|1不是合法的方案, 因为第一段“00”中夏之军人数为2,冬之军人数为0,人数之差的绝对值超过了K。
    【数据范围】
    20%的数据保证,N≤20。
    50%的数据保证,N≤8000。
    另有15%的数据保证,所有的人都是夏之军。
    另有15%的数据保证,K=0。
    100%的数据保证,1≤N≤10^5,0≤K≤N。
     
     
     
     
     
     
     
    比较明显的,这是一道dp;
    f[i]+=f[j] (i~j符合题中所说的要求);
    用s[i]表示原数组的前缀和,那么符合的条件就是:abs(2*s[i]-i+2*s[j-1]-(j-1))<=k
    那么设w[i]=2*s[i]-i;
    显然,w[i]-k<=w[j]<=w[i]+k
    发现了什么?转移的位置是一个连续区间;
    这时候我们就可以使用Splay或树状数组或线段树来大力维护dp状态;
    然后就可以AC掉了;
    注意w[i]-k有可能是负数,所以要将数组扩大几倍防止下标出现负数;

    #include <bits/stdc++.h>
    #pragma GCC optimize(2)
    #define p 1000000007
    #define inc(i,a,b) for(register int i=a;i<=b;i++)
    using namespace std;
    int a[100010],sum[100010];
    long long f[100010];
    long long ss[100010];
    int n,k;
    long long w[100010];
    long long c[600010];
    class node{
    	public:
    	inline int lowbit(register int x){
    		return x&(-x);
    	}
    	void add(register int x,register long long v){
    		while(x<=6*n){
    			c[x]=(c[x]+v)%p;
    			x+=lowbit(x);
    		}
    	}
    	int query(register int x){
    		register long long res=0;
    		while(x>0){
    			res=(res+c[x])%p;
    			x-=lowbit(x);
    		}
    		return res%p;
    	}
    }tree;
    template<class nT>
    inline void read(nT& x)
    {
    	char c;while(c=getchar(),!isdigit(c));
    	x=c^48;while(c=getchar(),isdigit(c)) x=x*10+c-48;
    }
    int main()
    {
    	read(n); read(k);
    	inc(i,1,n){
    		read(a[i]); sum[i]=(sum[i-1]+a[i]);	
    		w[i]=2*sum[i]-i;
    	}
    	f[0]=1;
    	tree.add(w[0]+2*n,1);
    	inc(i,1,n){
    		long long tmp1=tree.query(w[i]+k+2*n),tmp2=tree.query(w[i]-k-1+2*n);
    		long long tmp=((tmp1-tmp2)%p+p)%p;
    		f[i]=tmp%p;
    		tree.add(w[i]+2*n,f[i]);
    	}
    	cout<<f[n]%p;
    }
    /*
    2 1
    1 0
    
    3 0
    0 1 0
    
    30 7
    1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1
    
    49 17
    0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 0 1 1 0 1 1 0 1
    */
    
  • 相关阅读:
    zoj1151 zoj1295 Word Reversal 字符串的简单处理
    zoj 1539 Lot 简单DP 记忆化
    ZOJ 2042 Divisibility (DP)
    zoj 1889 ones 数学
    Kubernetes Ingress 日志分析与监控的最佳实践
    如何使用Data Lake Analytics创建分区表
    如何在Data Lake Analytics中使用临时表
    阿里敏捷教练:多团队开发一个产品的组织设计和思考
    阿里工程师开发了一款免费工具,提升Kubernetes应用开发效率
    触手可得的云原生 | 阿里云中间件发布多项新功能​
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11794467.html
Copyright © 2020-2023  润新知