题意

https://www.cometoj.com/contest/52/problem/C?problem_id=2416

思路

这里提供一种容斥的写法(?好像网上没看到这种写法)

题目要求编号为 \(i\) 的节点不能放在 \(p_i\) 位置,那我们不妨假设没有这些条件,然后再用二进制容斥的方法减去不满足条件的情况(即固定某些 \(i\) 在 \(p_i\) 上,这样会好考虑问题一点)。

然后我们面临的问题就是,计算 \(A\)(二进制)这些数不能选,\(B\)(二进制)这些位置不能填的方案数。我们枚举两个数,计算它们的对答案的贡献。设小的数为 \(i\) ,大的数为 \(j\) ,下面分四种情况讨论:

  • \(i,j\) 的位置均已确定

    若 \(p_i>p_j\) ,则造成 \((j-i)(p_i-p_j)(n-cnt_A)!\) 的贡献( \(cnt_A\) 为 \(A\) 的二进制中 \(1\) 的个数)。

  • \(j\) 的位置已经确定

    \(i\) 能选的位置为 \(\setminus A\)( \(A\) 对全集取补),尝试让 \(\setminus A\) 与 \(j\) 匹配,只有 \(\setminus A\) 中大于 \(j\) 的数才能得配,匹配结果是这个数减 \(j\) 。设 \(\setminus A\) 所有数的总匹配结果为 \(t\) ,它对答案的贡献即为 \((j-i)t(n-cnt_A-1)!\)

  • \(i\) 的位置已经确定

    与上一种其实没什么区别,只是 \(i\) 去匹配 \(\setminus A\) 罢了。

  • \(i,j\) 的位置均未确定

这次是一个集合匹配一个集合,在外面通过情况二来预处理。假设总匹配结果为 \(t\) ,对答案的贡献即为 \((j-i)t(n-cnt_A-2)\)

要注意固定数时如果有两个数共用了一个位置(即 \(p\) 相等),那这个贡献就直接为 \(0\) 了。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
#define lowbit(x) ((x)&-(x))
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
int cnt[(1<<16)+5],bin[(1<<16)+5],sum[(1<<16)+5];
int Sum[(1<<16)+5];
ll fac[18];
int n,p[18]; ll f1(int S,int pos)
{
S=(S|((1<<(pos+1))-1))^((1<<(pos+1))-1);
return sum[S]-cnt[S]*pos;
} ll f2(int pos,int S)
{
S=S&((1<<pos)-1);
return cnt[S]*pos-sum[S];
} ll solve(int A,int B)
{
ll ans=0;
FOR(i,0,n-1)FOR(j,i+1,n-1)
{
if((A>>i&1)&&(A>>j&1))
{
if(p[i]>p[j])
ans+=(j-i)*(p[i]-p[j])*fac[n-cnt[A]];
}
else if(!(A>>i&1)&&(A>>j&1))
{
ans+=(j-i)*f1(((1<<n)-1)^B,p[j])*fac[n-cnt[A]-1];
}
else if((A>>i&1)&&!(A>>j&1))
{
ans+=(j-i)*f2(p[i],((1<<n)-1)^B)*fac[n-cnt[A]-1];
}
else ans+=(j-i)*Sum[((1<<n)-1)^B]*fac[n-cnt[A]-2];
}
return ans;
} int main()
{
fac[0]=1;FOR(i,1,16)fac[i]=fac[i-1]*i;
FOR(i,1,1<<16)cnt[i]=cnt[i^lowbit(i)]+1;
FOR(i,2,1<<16)bin[i]=bin[i>>1]+1;
FOR(i,1,1<<16)sum[i]=sum[i^lowbit(i)]+bin[lowbit(i)];
FOR(i,1,1<<16)Sum[i]=Sum[i^lowbit(i)]+f1(i^lowbit(i),bin[lowbit(i)]);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
FOR(i,0,n-1)scanf("%d",&p[i]),p[i]--;
ll ans=0;
FOR(i,0,(1<<n)-1)
{
int S=0;
bool flg=1;
FOR(j,0,n-1)if(i>>j&1)
{
if(S&(1<<p[j]))
{
flg=0;
break;
}
S|=1<<p[j];
}
if(!flg)continue;
if(cnt[i]&1)ans-=solve(i,S);
else ans+=solve(i,S);
}
printf("%lld\n",ans);
}
return 0;
}

Comet OJ - Contest #7 C 临时翻出来的题(容斥+状压)的更多相关文章

  1. [Comet OJ - Contest #6 C][48C 2279]一道树题_树

    一道树题 题目大意: 给定一棵树,边的编号为读入顺序.现在规定,区间$[L, R]$的贡献$S(L,R)$为把编号在该区间里的边都连上后,当前形成的森林中点数大于等于$2$的联通块个数. 求$\sum ...

  2. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

  3. Comet OJ - Contest #2简要题解

    Comet OJ - Contest #2简要题解 前言: 我没有小裙子,我太菜了. A 因自过去而至的残响起舞 https://www.cometoj.com/contest/37/problem/ ...

  4. Comet OJ - Contest #4--前缀和

    原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...

  5. Comet OJ - Contest #11 题解&赛后总结

    Solution of Comet OJ - Contest #11 A.eon -Problem designed by Starria- 在模 10 意义下,答案变为最大数的最低位(即原数数位的最 ...

  6. Comet OJ - Contest #8

    Comet OJ - Contest #8 传送门 A.杀手皇后 签到. Code #include <bits/stdc++.h> using namespace std; typede ...

  7. Comet OJ - Contest #13-C2

    Comet OJ - Contest #13-C2 C2-佛御石之钵 -不碎的意志-」(困难版) 又是一道并查集.最近做过的并查集的题貌似蛮多的. 思路 首先考虑,每次处理矩形只考虑从0变成1的点.这 ...

  8. Comet OJ - Contest #13 「火鼠的皮衣 -不焦躁的内心-」

    来源:Comet OJ - Contest #13 芝士相关: 复平面在信息学奥赛中的应用[雾 其实是道 sb 题??? 发现原式貌似十分可二项式定理,然后发现确实如此 我们把 \(a^i\) 替换成 ...

  9. Comet OJ - Contest #13 「佛御石之钵 -不碎的意志-」(hard)

    来源:Comet OJ - Contest #13 一眼并查集,然后发现这题 tmd 要卡常数的说卧槽... 发现这里又要用并查集跳过访问点,又要用并查集维护联通块,于是开俩并查集分别维护就好了 一开 ...

随机推荐

  1. spring boot测试类自动注入service或dao

    使用Spring Boot进行单元测试时,发现使用@Autowired注解的类无法自动注入,当使用这个类的实例的时候,报出NullPointerException,即空指针异常. Spring Boo ...

  2. LeetCode Contest 166

    LeetCode Contest 166 第一次知道LeetCode 也有比赛. 很久没有打过这种线上的比赛,很激动. 直接写题解吧 第一题 很弱智 class Solution { public: ...

  3. shell脚本中判断进程是否存在

    #! /bin/bash PROC_NAME=docker ProcNumber=`ps -ef |grep -w $PROC_NAME|grep -v grep|wc -l` ];then echo ...

  4. C# 方法的out、ref、params参数

    一.out参数实例 [实例]求一个数组中的最大值.最小值.总和.平均值 class Program { static void Main(string[] args) { //写一个方法 求一个数组中 ...

  5. WPF 基础总结(学习建议)

    举个简单得例子, 类似造房子, 当然实际上可能非常细, 对应的如下所示: 在此之前, 需要了解的是. WPF项目是怎么启动的 Xaml的结构是怎么样组成, 命名控件定义引用的方法. 知道了如何在Xam ...

  6. Java多线程——查看线程堆栈信息

    Java多线程——查看线程堆栈信息 摘要:本文主要介绍了查看线程堆栈信息的方法. 使用Thread类的getAllStackTraces()方法 方法定义 可以看到getAllStackTraces( ...

  7. Spring Data Jpa:分页、Specification、Criteria

    分页的主要接口与类 PagingAndSortingRepository 继承自 CrudRepository 接口,提供了排序以及分页查询能力,提供了两个方法 Iterable<T> f ...

  8. web前端-js

    1. js基础语法 声明变量 var a = 10; 查看变量类型 typeof a; 打印,测试语句 alert(a); #使用弹出框显示 console.log(a);    #使用console ...

  9. 1021--RemoveOutermostParentheses

    public class RemoveOutermostParentheses { /* 解法一:栈,( 进栈,) 出栈,栈为空时,则找到原语,然后去括号. */ public String remo ...

  10. ngx-echarts 图表数据动态更新

    使用echarts绘制图表时,初次赋值数据正常展示,重新获取数据之后,图表没有跟着动态刷新.解决的办法是: html文件 <div echarts [options]="chartOp ...