题意

定义一个\(n*n\)的矩阵是\(beautiful\)的,需要满足以下三个条件:

1.每一行是一个排列。

2.上下相邻的两个元素的值不同。

再定义两个矩阵的字典序大的矩阵大(从左往右从上到下一个一个比较)。

给出一个\(beautiful\)的\(n*n\)的矩阵,求有多少个矩阵小于这个矩阵。

Solution

逐行计算。

\(ans=\)每行字典序比这行小的排列且与上一行相邻的两个元素值不同的排列个数*\(n\)个元素错排的方案数\(^{n-i}\)

第一行的方案数随便算,我就不说了。

另外的行大概就是逐位算。

从后往前枚举前\(i\)个数相同,树状数组维护当前位置可以填的数有几个有限制(即上一行后\(n-i+1\)中有这个数)和当前能填哪些数(即比\(a_{i,j}\)小且在当前行后\(n-i+1\)个数中出现了),不难发现有限制的数或者没限制的数都是同质的,那么就答案就是方案数乘上数的个数,问题就是有几个数有限制的错排怎么算方案数?\(dp\)一下就好了。

设\(dp_{i,j}\)表示\(i\)个数中有\(j\)个数有限制的排列的方案数。

考虑从\(dp_{i,j-1}\)转移,减去多了一个限制的数会少的方案数。

多了一个限制的数不合法的方案数?那我们就强制多的那个数不符合限制,另外数符合限制,也就是\(dp_{i-1,j-1}\)。

\(dp_{i,j}=dp_{i,j-1}-dp_{i-1,j-1}\)

如果不会推,也可以打表

\(dp_{n,n}\)的值就是\(n\)个数错排的方案数。

  1. #include<bits/stdc++.h>
  2. #define For(i,x,y) for (register int i=(x);i<=(y);i++)
  3. #define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
  4. #define cross(i,k) for (register int i=first[k];i;i=last[i])
  5. #define Debug(x) cerr<<#x<<"="<<(x)<<endl
  6. #define mp make_pair
  7. #define fi first
  8. #define se second
  9. using namespace std;
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pa;
  13. inline ll read(){
  14. ll x=0;int ch=getchar(),f=1;
  15. while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
  16. if (ch=='-'){f=-1;ch=getchar();}
  17. while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  18. return x*f;
  19. }
  20. const int N = 2010;
  21. int n,a[N][N];
  22. const int mod = 998244353;
  23. int fac[N],dp[N][N],p[N];
  24. inline void init(){
  25. fac[0]=1;For(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
  26. dp[1][0]=1;
  27. For(i,2,n){
  28. dp[i][0]=fac[i];
  29. For(j,1,i) dp[i][j]=(dp[i][j-1]-dp[i-1][j-1]+mod)%mod;
  30. }
  31. p[0]=1;For(i,1,n) p[i]=1ll*p[i-1]*dp[n][n]%mod;
  32. }
  33. struct BIT{
  34. int c[N],sum;
  35. inline void clear(){sum=0,memset(c,0,sizeof c);}
  36. inline void Add(int x){sum++;for (;x<=n;x+=x&-x) c[x]++;}
  37. inline int Query(int x){int ans=0;for (;x;x-=x&-x) ans+=c[x];return ans;}
  38. }t,T;
  39. int b[N],ans;
  40. inline void Add(int x){if (++b[x]==2) T.Add(x);}
  41. inline void upd(int &x,int y){x+=y,(x>=mod)?x-=mod:0;}
  42. int main(){
  43. n=read();
  44. For(i,1,n) For(j,1,n) a[i][j]=read();
  45. init();int sum=0;
  46. For(i,1,n) upd(sum,1ll*fac[n-i]*(a[1][i]-1-t.Query(a[1][i]-1))%mod),t.Add(a[1][i]);
  47. ans=1ll*sum*p[n-1]%mod;//printf("%d\n",ans);
  48. For(i,2,n){
  49. t.clear(),T.clear(),sum=0,memset(b,0,sizeof b);
  50. Dow(j,n,1){
  51. Add(a[i][j]),Add(a[i-1][j]),t.Add(a[i][j]);
  52. int x=T.Query(a[i][j]-1),y=t.Query(a[i][j]-1)-x,z=T.sum;
  53. if (b[a[i-1][j]]==2&&a[i-1][j]<a[i][j]) x--;
  54. if (b[a[i-1][j]]==2) z--;
  55. upd(sum,1ll*x*dp[n-j][z-1]%mod),upd(sum,1ll*y*dp[n-j][z]%mod);
  56. //printf("%d %d ",z,x*dp[n-j][z-1]);
  57. }//puts("");
  58. upd(ans,1ll*sum*p[n-i]%mod);
  59. }
  60. printf("%d\n",ans);
  61. }

Codeforces 1085G(1086E) Beautiful Matrix $dp$+树状数组的更多相关文章

  1. Codeforces Gym 100269F Flight Boarding Optimization 树状数组维护dp

    Flight Boarding Optimization 题目连接: http://codeforces.com/gym/100269/attachments Description Peter is ...

  2. Educational Codeforces Round 10 D. Nested Segments (树状数组)

    题目链接:http://codeforces.com/problemset/problem/652/D 给你n个不同的区间,L或者R不会出现相同的数字,问你每一个区间包含多少个区间. 我是先把每个区间 ...

  3. Codeforces Gym 100114 H. Milestones 离线树状数组

    H. Milestones Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descripti ...

  4. Codeforces - 828E DNA Evolution —— 很多棵树状数组

    题目链接:http://codeforces.com/contest/828/problem/E E. DNA Evolution time limit per test 2 seconds memo ...

  5. Codeforces 570D TREE REQUESTS dfs序+树状数组 异或

    http://codeforces.com/problemset/problem/570/D Tree Requests time limit per test 2 seconds memory li ...

  6. Codeforces 786C Till I Collapse(树状数组+扫描线+倍增)

    [题目链接] http://codeforces.com/contest/786/problem/C [题目大意] 给出一个数列,问对于不同的k,将区间划分为几个, 每个区间出现不同元素个数不超过k时 ...

  7. Codeforces 946G Almost Increasing Array (树状数组优化DP)

    题目链接   Educational Codeforces Round 39 Problem G 题意  给定一个序列,求把他变成Almost Increasing Array需要改变的最小元素个数. ...

  8. Codeforces 216D Spider&#39;s Web 树状数组+模拟

    题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,假设梯形左边的点数!=梯形右边的点数,那么这个梯形为红色.否则为绿色, ...

  9. CodeForces - 369E Valera and Queries(树状数组)

    CodeForces - 369E Valera and Queries 题目大意:给出n个线段(线段的左端点和右端点坐标)和m个查询,每个查询有cnt个点,要求给出有多少条线段包含至少其中一个点. ...

随机推荐

  1. Dream------scala--函数定义、流程控制、异常处理

    Dream------scala--函数定义.流程控制.异常处理 一.函数的定义 1.新建工程

  2. collision

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAd0AAACYCAIAAAAuvaRSAAAAA3NCSVQICAjb4U/gAAAgAElEQVR4Xu

  3. bash脚本里su命令执行

    俩种方法 1.可以使用 <<EOF 参数实现. 脚本内容:cat test.sh代码如下: #!/bin/bashsu - test <<EOFpwd;exit;EOF 2.当 ...

  4. 【bzoj3065】: 带插入区间K小值 详解——替罪羊套函数式线段树

    不得不说,做过最爽的树套树———— 由于有了区间操作,我们很容易把区间看成一棵平衡树,对他进行插入,那么外面一层就是平衡树了,这就与我们之前所见到的不同了.我们之前所见到的大多数是线段树套平衡树而此题 ...

  5. Java关于网络编程回顾

    一.Java网络编程三要素:1.IP地址:是要确定发送的地址,IP地址一般分为5类. 2.端口:要确定发送的程序是哪一个,端口的范围是0--65535,其中0-1024是系统使用或保留端口 3.协议: ...

  6. Flask:初见

    Windows 10家庭中文版,Python 3.6.4 从Flask官网开始学起. 介绍 Flask是一个Python的Web开发微框架,基于Werkzeug.Jinja2模块(and good i ...

  7. python基础--面向对象

    什么是面向对象编程 OOP编程是利用“类”和对象来创建各种模型来实现对真实世界的描述. OOP具有可维护性和可扩展性 二:面向对象有那些特性 1)CLASS类:一个类是对拥有相同属性的对象的抽象.类拥 ...

  8. Codeforces 801C Voltage Keepsake(二分枚举+浮点(模板))

    题目链接:http://codeforces.com/contest/801/problem/C 题目大意:给你一些电器以及他们的功率,还有一个功率一定的充电器可以给这些电器中的任意一个充电,并且不计 ...

  9. JAVA复习笔记分布式篇:kafka

    前言:第一次使用消息队列是在实在前年的时候,那时候还不了解kafka,用的是阿里的rocket_mq,当时觉得挺好用的,后来听原阿里的同事说rocket_mq是他们看来kafka的源码后自己开发了一套 ...

  10. Centos7.3安装和配置jre1.8

    在正式环境里 我们可以不安装jdk ,仅仅安装Java运行环境 jre即可: 第一步:下载jre 我们去oracle官方下载下jre http://www.oracle.com/technetwork ...