zoukankan      html  css  js  c++  java
  • NOI2016

    优秀的拆分

    Luogu
    LOJ
    UOJ
    BZOJ
    (f_i,g_i)分别表示以(i)结尾/开头的形如(AA)的串的个数,那么答案就是(sum f_ig_{i+1})
    考虑枚举(A)的长度(len),那么形如(AA)的串一定会过至少两个下标为(len)的倍数的位置(我们称之为关键位置)。
    对于任意相邻两个关键位置(i,j=i+len),它们对答案有(1)的贡献当且仅当(lcp(suf(i),suf(j))+lcs(pre(i-1),pre(j-1))ge len)
    (x=lcp(suf(i),suf(j)),y=lcs(pre(i-1),pre(j-1)),那么这个(AA)串的结尾可以落在([i-y,i+x-len+1))
    先维护(f,g)的差分再前缀和还原即可。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    int read(){int x;scanf("%d",&x);return x;}
    int min(int a,int b){return a<=b? a:b;}
    void swap(int &x,int &y){x^=y^=x^=y;}
    const int N=3e4+7;
    int t[N],x[N],y[N],Log[N],st[N],ed[N],n;
    void init(){memset(x,0,sizeof x),memset(y,0,sizeof y);}
    void Init(){memset(st,0,sizeof st),memset(ed,0,sizeof ed);}
    struct SuffixArray
    {
        int sa[N],rnk[N],h[N][20],m;
        char s[N];
        void rsort()
        {
    	for(int i=0;i<=m;++i) t[i]=0;
    	for(int i=1;i<=n;++i) ++t[x[y[i]]];
    	for(int i=1;i<=m;++i) t[i]+=t[i-1];
    	for(int i=n;i;--t[x[y[i]]],--i) sa[t[x[y[i]]]]=y[i];
        }
        void ssort()
        {
    	int i,l,p;
    	for(i=1;i<=n;++i) x[i]=s[i]-'a'+1,y[i]=i;
    	m=26,rsort();
    	for(l=1,p=0;p<n;m=p,l<<=1)
    	{
    	    for(p=0,i=n-l+1;i<=n;++i) y[++p]=i;
    	    for(i=1;i<=n;++i) if(sa[i]>l) y[++p]=sa[i]-l;
    	    rsort(),swap(x,y),x[sa[1]]=p=1;
    	    for(i=2;i<=n;++i) x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+l]==y[sa[i]+l])? p:++p;
    	}
        }
        void geth()
        {
    	int lcp=0,i,j;
    	for(i=1;i<=n;++i) rnk[sa[i]]=i;
    	for(i=1;i<=n;++i)
    	{
    	    if(lcp) --lcp;
    	    if(rnk[i]==n) continue;
    	    j=sa[rnk[i]+1];
    	    while(s[i+lcp]==s[j+lcp]) ++lcp;
    	    h[rnk[i]][0]=lcp;
    	}
    	for(i=1;i<=15;++i) for(j=1;j<=n&&j+(1<<i-1)<=n;++j) h[j][i]=min(h[j][i-1],h[j+(1<<i-1)][i-1]);
        }
        int LCP(int x,int y)
        {
    	x=rnk[x],y=rnk[y];
    	if(x>y) swap(x,y);
    	int k=Log[y-x];    
    	return min(h[x][k],h[y-(1<<k)][k]);
        }
    }A,B;
    int main()
    {
        int i,T=read(),j,x,y,t,len;
        LL ans;
        for(i=2;i<N;++i) Log[i]=Log[i>>1]+1;
        while(T--)
        {
    	Init(),init(),scanf("%s",A.s+1),n=strlen(A.s+1),A.ssort(),A.geth();
    	for(i=1;i<=n;++i) B.s[i]=A.s[n-i+1]; init(),B.ssort(),B.geth();
            for(len=1;len<=n>>1;++len)
                for(i=len,j=len<<1;j<=n;i+=len,j+=len)
    	    {
                    x=min(A.LCP(i,j),len),y=min(B.LCP(n-i+2,n-j+2),len-1);
                    if(x+y>=len) t=x+y-len+1,++st[i-y],--st[i-y+t],++ed[j+x-t],--ed[j+x];
                }
            for(i=1;i<=n;++i) st[i]+=st[i-1],ed[i]+=ed[i-1];
            for(ans=0,i=1;i<=n;++i) ans+=1ll*ed[i]*st[i+1];
            printf("%lld
    ",ans);
        }
    }
    

    网格

    Luogu
    LOJ
    UOJ
    BZOJ
    先特判掉答案为(-1)的情况,只有可能只剩一个格子,或者只剩两个相邻的格子。
    接下来如果答案为(0),那么说明原图已经不连通了。
    如果答案为(1),那么说明存在一个点把它删掉之后会使得图不连通(也就是割点)。
    那么将一个点为中心的(5 imes5)的网格的格子全部拿出来,跑一遍tarjin就行了。

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<utility>
    #include<algorithm>
    using pi=std::pair<int,int>;
    const int N=2500007;
    int n,m,c,tim,tot,ans,dfn[N],low[N],cut[N],is[N];std::map<pi,int>vis,id;
    pi a[N],b[N];std::set<pi>s;std::map<pi,int>A,B;std::queue<pi>q;std::vector<int>e[N];
    int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    void add(int u,int v){e[u].push_back(v),e[u].push_back(v),e[v].push_back(u),e[v].push_back(u);}
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tim;
        for(int v:e[u])
    	if(!dfn[v])
    	{
    	    tarjan(v),low[u]=std::min(low[u],low[v]);
    	    if(dfn[u]==low[v]) ++cut[u];
    	}
    	else low[u]=std::min(low[u],dfn[v]);
        if(((u!=1&&cut[u])||cut[u]>1)&&is[u]) ans=std::min(ans,1);
    }
    void bfs(pi x)
    {
        tim=tot=0,q.push(x),vis[x]=1;
        while(!q.empty())
        {
    	pi u=q.front();q.pop();
    	for(int i=-2;i<=2;++i)
    	    for(int j=-2;j<=2;++j)
    	    {
    		int x=u.first+i,y=u.second+j;pi v(x,y);
    		if(x<1||x>n||y<1||y>m) continue;
    		if(!s.count(v))
    		{
    		    if(!id[v]) id[v]=++tot,b[tot]=v;
    		    if(std::max(abs(i),abs(j))<2) is[id[v]]=1;
    		}
    		else if(!vis[v]) q.push(v),vis[v]=1;
    	    }
        }
        for(int i=1;i<=tot;++i)
        {
    	pi x(b[i].first+1,b[i].second);if(id[x])add(i,id[x]);
    	pi y(b[i].first,b[i].second+1);if(id[y])add(i,id[y]);
        }
        tarjan(1),memset(is+1,0,4*tot),memset(dfn+1,0,4*tot),memset(cut+1,0,4*tot),id.clear();
        for(int i=1;i<=tot;++i) e[i].clear();
        if(tim!=tot) ans=std::min(ans,0);
    }
    void solve()
    {
        n=read(),m=read(),c=read(),ans=2,s.clear(),vis.clear();
        for(int i=1;i<=c;++i) a[i].first=read(),a[i].second=read(),s.insert(a[i]);
        if(1ll*n*m-c<2) return puts("-1"),void();
        for(int i=1;i<=c;++i) if(!vis[a[i]]) bfs(a[i]);
        if(std::min(n,m)==1) ans=std::min(ans,1);
        if(1ll*n*m-c==2&&ans) ans=-1;
        printf("%d
    ",ans);
    }
    int main(){for(int t=read();t;--t)solve();}
    

    循环之美

    Luogu
    LOJ
    UOJ
    BZOJ

    [egin{aligned} ans=f(n,m,k)&=sumlimits_{i=1}^nsumlimits_{j=1}^m[iperp j][jperp k]\ &=sumlimits_{d|k}mu(d)sumlimits_{i=1}^nsumlimits_{j=1}^{lfloorfrac md floor}[iperp dj]\ &=sumlimits_{d|k}mu(d)sumlimits_{i=1}^nsumlimits_{j=1}^{lfloorfrac md floor}[iperp d][iperp j]\ &=sumlimits_{d|k}mu(d)f(frac md,n,d) end{aligned} ]

    [f(n,m,1)=sumlimits_{d=1}^nmu(d)lfloorfrac nd floorlfloorfrac md floor ]

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=1e7+7;
    struct node{int n,m,k;};
    int operator<(node a,node b){return a.n==b.n? (a.m==b.m? a.k<b.k:a.m<b.m):a.n<b.n;};
    int read(){int x;cin>>x;return x;}
    int lim,num[2000],flag[N],prime[N],mu[N],mus[N];
    map<int,int>mp;
    map<node,LL>Ans;
    int smu(int x)
    {
        if(x<=lim) return mus[x];
        if(mp[x]) return mp[x];
        int sum=1,i=2,j=sqrt(x);
        for(;i<=j;++i) sum-=smu(x/i);
        for(;i<=x;i=j+1) j=x/(x/i),sum-=(j-i+1)*smu(x/i);
        return mp[x]=sum;
    }
    LL solve(int n,int m,int k)
    {
        if(!n||!m) return 0;
        node tmp=node{n,m,k};
        LL sum=0;
        if(Ans[tmp])return Ans[tmp];
        if(k==1)
        {
            if(n>m) swap(n,m);
            int i,j,now,last;
            for(i=1,last=0;i<=n;i=j+1,last=now) j=min(n/(n/i),m/(m/i)),now=smu(j),sum+=1ll*(n/i)*(m/i)*(now-last);
            Ans[node{m,n,k}]=sum;
        }
        else for(int i=1;i<=num[0]&&num[i]<=k;++i) if(k%num[i]==0&&mu[num[i]]) sum+=solve(m/num[i],n,num[i])*mu[num[i]];
        return Ans[tmp]=sum;
    }
    int main()
    {
        int n=read(),m=read(),k=read(),i,j;lim=min(10000000,max(k,min(n,m))),mu[1]=1;
        for(i=2;i<=lim;++i)
        {
            if(!flag[i]) prime[++prime[0]]=i,mu[i]=-1;
            for(j=1;j<=prime[0]&&i*prime[j]<=lim;++j)
            {
                flag[i*prime[j]]=1;
                if(i%prime[j]) mu[i*prime[j]]=-mu[i]; else{mu[i*prime[j]]=0;break;}
            }
        }
        for(i=1;i<=lim;++i) mus[i]=mus[i-1]+mu[i];
        for(i=1;i<=k;++i) if(!(k%i)) num[++num[0]]=i;
        return !printf("%lld",solve(n,m,k));
    }
    

    区间

    Luogu
    LOJ
    UOJ
    BZOJ
    双指针+线段树。

    #include<bits/stdc++.h>
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],*iS,*iT;
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        int read(){int x=0;char ch=Get();while(ch>'9'||ch<'0')ch=Get();while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=Get();return x;}
    }
    using namespace IO;
    const int N=500001;
    struct node{int l,r,w;}a[N];
    bool operator<(node a,node b){return a.w<b.w;}
    int Hash[N<<1],tag[N<<3],sum[N<<3];
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define mid ((l+r)>>1)
    void modify(int p,int x){sum[p]+=x,tag[p]+=x;}
    void pushdown(int p){if(tag[p])modify(ls,tag[p]),modify(rs,tag[p]),tag[p]=0;}
    void pushup(int p){sum[p]=max(sum[ls],sum[rs]);}
    void update(int p,int l,int r,int L,int R,int x)
    {
        if(L>r||l>R) return;
        if(L<=l&&r<=R) return modify(p,x);
        pushdown(p),update(ls,l,mid,L,R,x),update(rs,mid+1,r,L,R,x),pushup(p);
    }
    #undef ls
    #undef rs
    #undef mid
    int main()
    {
        int n=read(),m=read(),num,Min=2147483647,Max=0,head=0,tail=0,ans=2147483647;
        for(int i=1,tot=0;i<=n;++i) Hash[++tot]=a[i].l=read(),Hash[++tot]=a[i].r=read(),a[i].w=a[i].r-a[i].l;
        sort(Hash+1,Hash+(n<<1)+1),num=unique(Hash+1,Hash+(n<<1)+1)-(Hash+1),sort(a+1,a+n+1);
        for(int i=1;i<=n;++i) Min=min(Min,a[i].l=lower_bound(Hash+1,Hash+num+1,a[i].l)-Hash),Max=max(Max,a[i].r=lower_bound(Hash+1,Hash+num+1,a[i].r)-Hash);
        while(tail<n)
        {
    	while(sum[1]<m&&tail<=n) ++tail,update(1,Min,Max,a[tail].l,a[tail].r,1);
    	if(sum[1]<m) break;
    	while(sum[1]>=m&&tail>=head) ++head,update(1,Min,Max,a[head].l,a[head].r,-1);
    	ans=min(ans,a[tail].w-a[head].w);
        }
        if(ans==2147483647) ans=-1;
        return cout<<ans,0;
    }
    

    国王饮水记

    Luogu
    LOJ
    UOJ
    BZOJ
    把所有城市按水位高度降序排序,那么在首都后面的城市可以忽略了。
    首先如果没有限制,那么最优策略是每次找水位高度比首都高的最低的城市合并。
    现在有了次数限制之后不能这么做了,但是我们知道合并过的城市一定是一段前缀。
    (f_{i,j})表示前(j)个城市合并了(i)次的最优答案。记(sum_i)为前(i)个城市的水位高度之和。
    转移方程为(f_{i,j}=max(frac{f(i-1,k)+(sum_j-sum_k)}{j-k+1})),斜率优化即可。

    #include<bits/stdc++.h>
    #define P pair<int,double>
    using namespace std;
    int read(){int x;cin>>x;return x;}
    const int N=8192;
    int h[N],s[N],a[400],g[16][N],v[16],p;
    double f[16][N];
    P q[N],A,B;
    double operator%(P a,P b){return (b.second-a.second)/(b.first-a.first);}
    void div(int x)
    {
        long long q=0;
        for(int i=0;i<=p;++i) q=q*1000000000+a[i],a[i]=q/x,q%=x;
    }
    int main()
    {
        int k=read(),n,m=read(),x,i,j,l,hd,tl;p=read()/9+1;
        for(h[n=1]=read(),i=2;i<=k;++i) if((x=read())>h[1]) h[++n]=x;
        for(sort(h+1,h+n+1),m=min(n,m),i=1;i<=n;++i) f[0][i]=h[1],s[i]=s[i-1]+h[i];
        for(l=min(m,14),i=1;i<=l;++i)
            for(j=2,hd=1,tl=0;j<=n;++j)
    	{
                A=P(j-2,s[j-1]-f[i-1][j-1]);
                while(hd<tl&&q[tl-1]%q[tl]>q[tl]%A) --tl;
                q[++tl]=A,B=P(j,s[j]);
                while(hd<tl&&q[hd]%B<q[hd+1]%B) ++hd;
                g[i][j]=q[hd].first+1,f[i][j]=q[hd]%B;
            }
        for(v[l]=n-m+l,i=l;i;--i) v[i-1]=g[i][v[i]];
        for(a[0]=h[1],i=1;i<=l;++i) a[0]+=s[v[i]]-s[v[i-1]],div(v[i]-v[i-1]+1);
        for(i=v[l]+1;i<=n;++i) a[0]+=h[i],div(2);
        for(printf("%d.",a[0]),i=1;i<=p;++i) printf("%09d",a[i]);
    }
    
  • 相关阅读:
    Java上等价类划分测试的实现
    软件测试の因果图法的测试运用
    display: block; 和 display: inline; 的区别
    CSS实现垂直居中
    CSS中实现水平居中
    HTTP头部信息
    HTTP PUT方法和POST方法的区别
    理解 ajax xhr jsonp
    深入理解JavaScript系列
    Angular 1.x 指令笔记
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13019222.html
Copyright © 2011-2022 走看看