zoukankan      html  css  js  c++  java
  • BZOJ4406 WC2016 论战捆竹竿

    Problem

    BZOJ

    Solution

    显然是一个同余系最短路问题,转移方案就是所有|S|-border的长度,有 (O(n)) 种,暴力跑dijkstra的复杂度为 (O(n^2log n))

    有一个结论,一个字符串的border的长度可以被分为 (log |S|) 个等差数列。

    那么我们不如来考虑一个等差数列所造成的影响,设等差数列共有 (m) 项,初值为 (x) ,那么它可以被表示为 ({ kd+x,kin[0,m)})

    [f[i]=min_{j=0}^{m-1}(f[(i-x-jd)mod n]+x+jd) ]

    如果我们能建立一个 (mod x) 的剩余系,那么接下来就相当于添加了一个 (+d) 的转移方案,但是这个转移有距离的限制。注意到能相互更新的状态会形成 (gcd(x,d)) 个环,可以套路地拆下来并倍长,用单调队列即可解决距离的限制,时间复杂度为 (O(x))

    那么就只需要解决两个剩余系相互转化的问题了。其实很简单,设旧表的模数为 (p),新表的模数为 (q),只需要把旧表中每一列的最小能表达的值作为初始值放入新表中,然后只需要把转移方案 (+p) 加入表中,更新一次即可,这样的复杂度是 (O(q)) 的。

    总的时间复杂度为 (O(sum nlog n))

    注意把用来存border的数组,把a[len+1]的值清为0,这样才不会导致判的等差数列。

    Code

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=500010;
    template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
    template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
    template <typename Tp> inline void read(Tp &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=1,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        if(f) x=-x;
    }
    int z,n,k,tot,top,now,nxt[maxn],a[maxn],stk[maxn<<1];
    int l,r,q[maxn<<1];
    ll w,ans,f[maxn],g[maxn];
    char s[maxn];
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    void trans(int x)
    {
    	int D=gcd(x,now);
    	memset(g,0x3f,x<<3);
    	for(int i=0;i<now;i++) getmin(g[f[i]%x],f[i]);
    	for(int i=0;i<D;i++)
    	{
    		top=0;
    		for(int j=i;top==0||j!=i;j=(j+now)%x) stk[++top]=j;
    		for(int j=1;j<=top;j++) stk[j+top]=stk[j];
    		top<<=1;
    		for(int j=2;j<=top;j++)
    		  getmin(g[stk[j]],g[stk[j-1]]+now);
    	}
    	memmove(f,g,x<<3);
    	now=x;
    }
    void solve(int x,int d,int m)
    {
    	trans(x);
    	if(d<0) return ;
    	int D=gcd(x,d);
    	for(int i=0;i<D;i++)
    	{
    		top=0;l=1;r=0;
    		for(int j=i;top==0||j!=i;j=(j+d)%x) stk[++top]=j;
    		for(int j=1;j<=top;j++) stk[j+top]=stk[j];
    		top<<=1;
    		for(int j=1;j<=top;j++)
    		{
    			while(l<=r&&j-q[l]>=m) ++l;
    			if(l<=r) getmin(f[stk[j]],f[stk[q[l]]]+(j-q[l])*d+x);
    			while(l<=r&&f[stk[q[r]]]+(j-q[r])*d>f[stk[j]]) --r;
    			q[++r]=j;
    		}
    	}
    }
    int main()
    {
    	read(z);
    	while(z--)
    	{
    		read(n);read(w);scanf("%s",s);
    		ans=tot=k=0;memset(f,0x3f,n<<3);
    		for(int i=1;i<n;i++)
    		{
    			while(k&&s[k]!=s[i]) k=nxt[k];
    			if(s[k]==s[i]) nxt[i+1]=++k;
    			else nxt[i+1]=0;
    		}
    		for(int i=nxt[n];i;i=nxt[i]) a[++tot]=n-i;
    		now=n;f[0]=n;a[tot+1]=0;
    		for(int i=1,j=1;i<=tot;i=j)
    		{
    			while(a[j+1]-a[j]==a[i+1]-a[i]) j++;
    			solve(a[i],a[i+1]-a[i],j-i);
    		}
    		for(int i=0;i<now;i++) if(f[i]<=w) ans+=(w-f[i])/now+1;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysql 从5.1升级到5.5.33 后 innodb 表出错 及 innodb表修复
    (未解决)在JSTL中,session 和 sessionScope 有什么区别 ??
    ubuntu 12.04安装redis2.6.16
    SOA,不看你永远不知道的事
    Failed to retrieve procctx from ht. constr
    CUSPARSE 第三章 CUSPARAE索引和数据格式
    yii框架网址解析问题
    以图搜图相关资料
    JMeter工具的使用-ForEach
    [cocos2d-x]针对不同的设备,选取不同的自适应图片
  • 原文地址:https://www.cnblogs.com/totorato/p/10904573.html
Copyright © 2011-2022 走看看