n <= 60w,∑n <= 200w,1s。

解:首先有个全排列 + 树状数组的暴力。

然后有个没有任何规律的状压...首先我想的是按照大小顺序来放数,可以分为确定绝对位置和相对位置两种,但是都不好处理字典序。

然后换个思路一位一位的考虑放哪个数。用一维来记录|i - pi| - 逆序对数 * 2,还有一维记录是否紧贴下限,一个二进制数记录之前填了哪些数。

当前填到哪一位可以通过二进制中1的个数统计出来。这样就是一个n32n的做法,可以过n <= 14的点,得到24分。

 /**
* There is no end though there is a start in space. ---Infinity.
* It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
* Only the person who was wisdom can read the most foolish one from the history.
* The fish that lives in the sea doesn't know the world in the land.
* It also ruins and goes if they have wisdom.
* It is funnier that man exceeds the speed of light than fish start living in the land.
* It can be said that this is an final ultimatum from the god to the people who can fight.
*
* Steins;Gate
*/ #include <bits/stdc++.h> const int N = , MO = ; int p[N], n; inline void Add(int &a, const int &b) {
a += b;
while(a >= MO) a -= MO;
while(a < ) a += MO;
return;
} inline void out(int x) {
for(int i = ; i < n; i++) {
printf("%d", (x >> i) & );
}
return;
} namespace Sta {
const int DT = , M = ;
int f[DT * ][M][], cnt[M], pw[M];
inline void prework() {
for(int i = ; i < M; i++) {
cnt[i] = + cnt[i - (i & (-i))];
}
for(int i = ; i < M; i++) {
pw[i] = pw[i >> ] + ;
}
return;
}
inline void solve() {
memset(f, , sizeof(f));
f[DT][][] = ;
/// DP
int lm = ( << n) - , lm2 = n * (n - ) / ; /// lm : 11111111111
for(int s = ; s < lm; s++) {
for(int i = -lm2; i <= lm2; i++) {
/// f[i + DT][s][0/1]
if(!f[i + DT][s][] && !f[i + DT][s][]) continue;
//printf("f %d ", i); out(s); printf(" 0 = %d 1 = %d \n", f[i + DT][s][0], f[i + DT][s][1]);
int t = lm ^ s;
while(t) {
int j = pw[t & (-t)] + , temp = i + std::abs(cnt[s] + - j) - cnt[s >> (j - )] * + DT, t2 = s | ( << (j - ));
/// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1]
Add(f[temp][t2][1], f[i + DT][s][1]);
//printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]);
if(j > p[cnt[s] + ]) {
Add(f[temp][t2][], f[i + DT][s][]);
//printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]);
}
else if(j == p[cnt[s] + ]) {
Add(f[temp][t2][], f[i + DT][s][]);
//printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d\n", f[temp][t2][0]);
}
t ^= << (j - );
}
}
} printf("%d\n", f[DT][lm][]);
return;
}
} int main() {
//printf("%d \n", (sizeof(Sta::f)) / 1048576);
int T;
scanf("%d", &T);
Sta::prework();
while(T--) {
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &p[i]);
}
Sta::solve();
}
return ;
}

24分状压

然后我们必须开始找规律了......这里我是完全没思路(太过SB)

冷静分析一波发现,一个合法的排列等价于一个不存在长度为三的下降子序列的排列。

因为如果存在长度为3的下降子序列,那么中间那个元素一定有一次移动不是如它所想的。而不存在的话,我们就可以归纳,冒泡排序每一步都会减少一对逆序对,下降子序列一定不会变长。(全是口胡,意会就行了)

然后有一个44分的状压DP出来了,我没写...

80分n2DP,先考虑怎么求答案。枚举哪个位置开始自由,如果在i开始自由的话就要知道后面有多少种填法。所以我们需要一个从当前状态到终态的状态,而不是从初态到当前。

(看题解)发现如果前缀最大值为j,那么当前要么填比j小的最小的,要么填比j大的。因为如果填了比j小的又不是最小的,就会有一个长为3的下降子序列。

然后设fi,j表示还剩i位要填,能填的数中比max(1~i)大的有j个,填满的方案数。

于是有f[i][j] = ∑f[i - 1][k] = f[i][j - 1] + f[i - 1][j]

于是枚举在哪自由,然后把对应的j求出来。每个位置要加上fn-i,0~j-1

注意有两个地方要break,一个是后面没有比max(1~i)大的数了,还有就是当前填了长为3的下降子序列了。

100分:发现f这个东西其实就是格路径方案数......特别注意i < j的时候为0,所以有一条线不能跨过......

组合数学一波,就能O(1)计算f了。然后发现这个东西fn-i,0~j-1不就是fn-i+1,j-1吗?然后就完事了,nlogn。

 /**
* There is no end though there is a start in space. ---Infinity.
* It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
* Only the person who was wisdom can read the most foolish one from the history.
* The fish that lives in the sea doesn't know the world in the land.
* It also ruins and goes if they have wisdom.
* It is funnier that man exceeds the speed of light than fish start living in the land.
* It can be said that this is an final ultimatum from the god to the people who can fight.
*
* Steins;Gate
*/ #include <bits/stdc++.h> typedef long long LL;
const int N = , MO = ; int p[N], n;
int fac[N << ], inv[N << ], invn[N << ]; inline LL C(int n, int m) {
if(n < || m < || n < m) return ;
return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
} inline void Add(int &a, const int &b) {
a += b;
while(a >= MO) a -= MO;
while(a < ) a += MO;
return;
} inline void out(int x) {
for(int i = ; i < n; i++) {
printf("%d", (x >> i) & );
}
return;
} namespace Sta {
const int DT = , M = ;
int f[DT * ][M][], cnt[M], pw[M];
inline void prework() {
for(int i = ; i < M; i++) {
cnt[i] = + cnt[i - (i & (-i))];
}
for(int i = ; i < M; i++) {
pw[i] = pw[i >> ] + ;
}
return;
}
inline void solve() {
memset(f, , sizeof(f));
f[DT][][] = ;
/// DP
int lm = ( << n) - , lm2 = n * (n - ) / ; /// lm : 11111111111
for(int s = ; s < lm; s++) {
for(int i = -lm2; i <= lm2; i++) {
/// f[i + DT][s][0/1]
if(!f[i + DT][s][] && !f[i + DT][s][]) continue;
//printf("f %d ", i); out(s); printf(" 0 = %d 1 = %d \n", f[i + DT][s][0], f[i + DT][s][1]);
int t = lm ^ s;
while(t) {
int j = pw[t & (-t)] + , temp = i + std::abs(cnt[s] + - j) - cnt[s >> (j - )] * + DT, t2 = s | ( << (j - ));
/// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1]
Add(f[temp][t2][1], f[i + DT][s][1]);
//printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]);
if(j > p[cnt[s] + ]) {
Add(f[temp][t2][], f[i + DT][s][]);
//printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]);
}
else if(j == p[cnt[s] + ]) {
Add(f[temp][t2][], f[i + DT][s][]);
//printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d\n", f[temp][t2][0]);
}
t ^= << (j - );
}
}
} printf("%d\n", f[DT][lm][]);
return;
}
} namespace Stable { int ta[N]; inline void add(int i) {
for(; i <= n; i += i & (-i)) ta[i]++;
return;
}
inline int ask(int i) {
int ans = ;
for(; i; i -= i & (-i)) {
ans += ta[i];
}
return ans;
}
inline void clear() {
memset(ta + , , n * sizeof(int));
return;
} inline bool check() {
int ans = , cnt = ;
for(int i = n; i >= ; i--) {
cnt += std::abs(i - p[i]);
ans += ask(p[i] - );
add(p[i]);
}
clear();
return cnt == ans * ;
} inline int cal() {
int ans = ;
for(int i = ; i <= n; i++) {
if(p[i] < p[i - ]) ans++;
}
return ans + ;
} inline void work() {
for(n = ; n <= ; n++) {
for(int i = ; i <= n; i++) p[i] = i;
do {
if(check()) {
for(int i = ; i <= n; i++) {
printf("%d ", p[i]);
}
}
else {
printf("ERR : ");
for(int i = ; i <= n; i++) {
printf("%d ", p[i]);
}
}
printf(" cal = %d \n", cal());
} while(std::next_permutation(p + , p + n + ));
getchar();
}
return;
}
} namespace DP {
const int M = ;
int f[M][M], ta[N];
inline void add(int i) {
for(; i <= n; i += i & (-i)) ta[i]++;
return;
}
inline int ask(int i) {
int ans = ;
for(; i; i -= i & (-i)) {
ans += ta[i];
}
return ans;
}
inline int getSum(int l, int r) {
return ask(r) - ask(l - );
}
inline int F(int i, int j) {
if(i < j) return ;
return (C(i + j - , j) - C(i + j - , i + ) + MO) % MO;
}
inline void solve() {
/*memset(f, 0, sizeof(f));
f[0][0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= i; j++) {
f[i][j] = (f[i - 1][j] + f[i][j - 1]) % MO;
}
}*/ /*for(int j = n; j >= 0; j--) {
for(int i = 0; i <= n; i++) {
printf("%3d ", f[i][j]);
}
puts("");
}*/ int ans = , pre = ;
for(int i = ; i < n; i++) {
/// [1, i - 1] == i >
pre = std::max(pre, p[i]);
int k = n - pre - getSum(pre + , n);
//printf("i = %d k = %d \n", i, k);
if(!k) break;
/*for(int j = 0; j < k; j++) {
Add(ans, F(n - i, j));
//printf("add f %d %d \n", n - i, j);
}*/
Add(ans, F(n - i + , k - ));
add(p[i]);
if(p[i] < pre && ask(p[i]) != p[i]) break;
}
printf("%d\n", ans);
memset(ta + , , n * sizeof(int));
return;
}
} int main() {
//printf("%d \n", (sizeof(Sta::f)) / 1048576);
//Stable::work();
fac[] = inv[] = invn[] = ;
fac[] = inv[] = invn[] = ;
for(int i = ; i < N * ; i++) {
fac[i] = 1ll * fac[i - ] * i % MO;
inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
invn[i] = 1ll * invn[i - ] * inv[i] % MO;
}
int T;
scanf("%d", &T);
//Sta::prework();
while(T--) {
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &p[i]);
}
DP::solve();
}
return ;
}

AC代码

洛谷P4769 冒泡排序的更多相关文章

  1. 【洛谷4769】[NOI2018] 冒泡排序(动态规划_组合数学)

    题目: 洛谷 4769 博客页面左下角的嘴嘴瓜封神之战中的题目 分析: 一个排列交换次数为 \(\frac{1}{2}\sum_{i=1}^{n}|i-p_i|\) 的充要条件是这个排列不存在长度为 ...

  2. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

  3. P1075,P1138(洛谷)

    今天难得做了做洛谷的题,而且还是两个! P1075:已知正整数n是两个不同的质数的乘积,试求出两者中较大的那个质数.输入格式:一个正整数n.输出格式:一个正整数p,即较大的那个质数. 第一版代码: # ...

  4. 快速排序--洛谷卡TLE后最终我还是选择了三向切割

    写在前边 这篇文章呢,我们接着聊一下排序算法,我们之前已经谈到了简单插入排序 和ta的优化版希尔排序,这节我们要接触一个更"高级"的算法了--快速排序. 在做洛谷的时候,遇到了一道 ...

  5. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  6. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  7. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  8. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  9. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

随机推荐

  1. VUE.JS 使用axios数据请求时数据绑定时 报错 TypeError: Cannot set property 'xxxx' of undefined 的解决办法

    正常情况下在data里面都有做了定义 在函数里面进行赋值 这时候你运行时会发现,数据可以请求到,但是会报错 TypeError: Cannot set property 'listgroup' of ...

  2. Mapper动态代理方式

    开发规范 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同Dao接口实现类方法. Mapper接 ...

  3. 在windows 7 和linux上安装xlwt和xlrd

    在windows 7上安装xlwt xlrd xlwt是开源社区编写的python库,需要单独安装,下载地址https://pypi.python.org/pypi/xlwt 目前xlwt最新的版本是 ...

  4. Fiddler-学习笔记-远程抓包

    1 操作系统低于win7用 fiddler 2 win7 或win7以上版本,用 fiddler4片本 2 fiddler开关:左下角或点击F12控件fiddler开关,开=capturing 3 启 ...

  5. delphi 怎么实现主窗口退出时,有一个提示框?

    无论点窗口上的[按钮]还是[右上角的叉],能出现一个提示窗口,“是”-退出窗口,“否”-重新登录(调出登录窗口),“取消”-返回.MessageBox能实现吗?还是要调用新窗口(我调用窗口,有些错误) ...

  6. C-Lodop设置页面一加载就打印

    C-Lodop由于是服务不是np插件,调用打印语句(print或preview等)时机太早,在页面第一次加载完成后有几百毫秒时间等待WebSocket通讯服务准备完成,在没完成的时候会提示“C-Lod ...

  7. How to mount EFI on macOS

    mount -t msdos /dev/disk0s1 /volumes/efi

  8. codeforces484A

    Bits CodeForces - 484A Let's denote as  the number of bits set ('1' bits) in the binary representati ...

  9. float数组转字符串实施方案小记

    float[] floats = {1.2f , 3.5f , 6.4f}; Double[] doubles = IntStream.range(0, floats.length).mapToDou ...

  10. POJ 2750 鸡兔同笼

    参考自:https://www.cnblogs.com/ECJTUACM-873284962/p/6414781.html POJ 2750鸡兔同笼 总时间限制:1000ms 内存限制:65536kB ...