zoukankan      html  css  js  c++  java
  • 神在夏至祭降下了神谕 题解

      先说一句题外话,有谁看到的第一眼看成了某站的知名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
    */
    
  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11794467.html
Copyright © 2011-2022 走看看