令$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$为右端点的区间,即仅保留$j\in [L_{j}(i),R_{j}(i)]$且$k\in [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\n",ans);
72 }
73 return 0;
74 }

最新文章

  1. 分离与继承的思想实现图片上传后的预览功能:ImageUploadView
  2. xutils3
  3. Jsp与servlet本质上的区别
  4. 我所了解的meta
  5. P6 EPPM 16.1 安装和配置指南 1
  6. 一个备份MySQL数据库的简单Shell脚本(转)
  7. iOS 语音识别使用讯飞报错
  8. 用SQL脚本移除视图中存在的机器名
  9. CentOS 安装easy_install、pip的方法
  10. 【原创】构建高性能ASP.NET站点之三 细节决定成败
  11. As3.0 TextField
  12. php表单提交--文件
  13. 带三方登录(qq,微信,微博)
  14. 通用mapper认识和用法
  15. [leetcode]224. Basic Calculator
  16. 缓存数据库Memcache
  17. Android 源码分析01_AsyncTask
  18. HDU_1142(最短路 + dfs)
  19. MySQL读写分离-简单思考
  20. FPGA远程更新之限制条件

热门文章

  1. 小白自制Linux开发板 三. Linux内核与文件系统移植
  2. JUC之Executor,ExecutorService接口,AbstractExecutorService类
  3. CF1082E Increasing Frequency (multiset+乱搞+贪心)
  4. luogu1438无聊的数列(区间加等差数列,求一个数的和)
  5. 北鲲云超算如何让仿真技术、HPC和人工智能之间的深度融合?
  6. SpringBoot入门03-转发到Thymeleaf
  7. 试题 算法训练 二进制数数 java解题
  8. Arthas 进阶教程
  9. 八大排序算法之基数排序(python实现)
  10. ssh后门反向代理实现内网穿透