zoukankan      html  css  js  c++  java
  • [Comet1790]Ternary String Counting

    令$f_{i,j,k}$表示前$i$个位置,三种字符最后一次出现的位置为$i,j$和$k$(保证$k<j<i$)的方案数

    考虑转移(递推),即分为两步——

    1.填写第$i$个字符,即从$f_{i-1,j,k}$转移到$f_{i,j,k},f_{i,i-1,j}$或$f_{i,i-1,k}$

    2.考虑以$i$为右端点的区间,即仅保留$jin [L_{j}(i),R_{j}(i)]$且$kin [L_{k}(i),R_{k}(i)]$的位置(其余位置清0)

    (关于$L/R_{j/k}(i)$显然可以$o(m)$预处理出)

    暴力转移复杂度为$o(n^{3})$,考虑优化——

    关于第一步,如果将$i$滚动,实际上修改的位置仅有$o(n)$个,而修改的值即某行/列的元素和,那么再额外维护该信息,同时修改也可以继续维护,复杂度降为$o(n^{2})$

    关于第二步,注意到一个位置被清0后不会再有值,那么只需要快速找到需要清0且非0的位置,这可以对每行维护一个双向队列来实现,进而均摊复杂度也降为$o(n^{2})$

    最终,总复杂度为$o(n^{2}+m)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 5005 
     4 #define mod 1000000007
     5 deque<int>q[N];
     6 int t,n,m,l,r,x,ans,Lj[N],Rj[N],Lk[N],Rk[N],sr[N],sc[N],f[N][N];
     7 int read(){
     8     int x=0;
     9     char c=getchar();
    10     while ((c<'0')||(c>'9'))c=getchar();
    11     while ((c>='0')&&(c<='9')){
    12         x=x*10+c-'0';
    13         c=getchar();
    14     }
    15     return x;
    16 }
    17 void upd(int x,int y,int z){
    18     q[y].push_back(x);
    19     sr[x]=(sr[x]+z)%mod;
    20     sc[y]=(sc[y]+z)%mod;
    21     f[x][y]=(f[x][y]+z)%mod;
    22 }
    23 void clear_l(int y){
    24     int x=q[y].front();
    25     q[y].pop_front();
    26     sr[x]=(sr[x]-f[x][y]+mod)%mod;
    27     sc[y]=(sc[y]-f[x][y]+mod)%mod;
    28     f[x][y]=0;
    29 }
    30 void clear_r(int y){
    31     int x=q[y].back();
    32     q[y].pop_back();
    33     sr[x]=(sr[x]-f[x][y]+mod)%mod;
    34     sc[y]=(sc[y]-f[x][y]+mod)%mod;
    35     f[x][y]=0;
    36 }
    37 int main(){
    38     t=read();
    39     while (t--){
    40         n=read(),m=read();
    41         for(int i=1;i<=n;i++){
    42             Lj[i]=Lk[i]=0;
    43             Rj[i]=Rk[i]=i-1;
    44         }
    45         for(int i=1;i<=m;i++){
    46             l=read(),r=read(),x=read();
    47             if (x==1)Rj[r]=min(Rj[r],l-1);
    48             if (x==2)Lj[r]=max(Lj[r],l),Rk[r]=min(Rk[r],l-1);
    49             if (x==3)Lk[r]=max(Lk[r],l);
    50         }
    51         memset(sr,0,sizeof(sr));
    52         memset(sc,0,sizeof(sc));
    53         memset(f,0,sizeof(f));
    54         for(int i=0;i<n;i++)q[i].clear();
    55         upd(0,0,1);
    56         for(int i=1;i<=n;i++){
    57             for(int j=0;j<max(i-1,1);j++)upd(i-1,j,(sr[j]+sc[j])%mod);
    58             for(int j=0;j<i;j++){
    59                 if ((Lk[i]<=j)&&(j<=Rk[i])){
    60                     while ((!q[j].empty())&&(q[j].front()<Lj[i]))clear_l(j);
    61                     while ((!q[j].empty())&&(q[j].back()>Rj[i]))clear_r(j);
    62                 }
    63                 else{
    64                     while (!q[j].empty())clear_l(j);
    65                 }
    66             }
    67         }
    68         ans=0;
    69         for(int i=0;i<n;i++)
    70             for(int j=0;j<n;j++)ans=(ans+f[i][j])%mod;
    71         printf("%d
    ",ans);
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    插入排序
    JavaMail学习笔记
    Struts2的工作原理
    我的快速排序
    截取字符串,只截取前N个字节的字符
    修改MyEclipse8.6中的Servlet.java模板
    Java类装载的过程及原理介绍
    cmd检查jdk的版本
    快速排序
    flash 侦测人的面部
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15465789.html
Copyright © 2011-2022 走看看