作业

poj 1091 跳蚤

容斥原理。

考虑能否跳到旁边就是卡牌的\(gcd\)是否是1,可以根据裴蜀定理证明。

考虑正着做十分的麻烦,所以倒着做,也就是用\(M^N - (不合法)\)即可。

不合法显然就是\(gcd\)不为1的情况,那么我们考虑枚举\(gcd\),\((1 \leq gcd \leq 15)\),第\(n + 1\)个数一直是\(m\)所以不用理它。

考虑每个\(gcd\)的贡献,如果所有的都能被整除,那么产生的方案数就是:

\(({m \over gcd})^n\)

表示在小于等于\(m\)的数中有多少能够被当前的\(gcd\)整除,那么每个位置就有这么多数字可以选择,就转化成了容斥原理的问题了,\(dfs\)枚举\(m\)的质因数统计即可。

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define int long long
int n,m;
const int MAXN = 1e5 + 10;
int Ans;
int p[MAXN];
int ans;
int div (int now) {
int res = 0;
for(int i = 2;i * i <= now; ++i) {
if(now % i == 0) {
p[++res] = i;
now /= i;
while(now % i == 0) now /= i;
}
}
if(now > 1) p[++res] = now;
return res;
} int pow_mod(int a,int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
} void dfs(int num,int y,int now) {
if(now > m) return;
if(num == ans + 1) {
if(y) {
if(y & 1) {
Ans -= pow_mod(m / now,n);
}
else {
Ans += pow_mod(m / now,n);
}
}
return;
}
dfs(num + 1,y,now);
dfs(num + 1,y + 1,now * p[num]);
} signed main () {
cin >> n >> m;
Ans = pow_mod(m,n);
//cout<<Ans<<endl;
ans = div(m);
//cout<<ans<<endl;
dfs(1,0,1);
cout<<Ans<<endl;
return 0;
}

ps:这题为啥不用取模?真是让人难以琢磨。

hdu 5121 just a mistake

期望\(dp\)+容斥原理

题目大意就是让你随机构造一个排列,然后判断是否与集合中的点有连边然后一个一个的连接。

乍一看十分难做,第二眼还是十分难做,做了\(1h23min\)。。。

首先考虑如何统计贡献,一般的方程就是如果第\(i\)是\(p_i\)的时候,某些贡献是多少,由于这个问题拓展到了树上,那么就是设\(f_{i,j}\)表示以\(i\)为根的子树中,\(i\)排在第\(j\)位且必须选的方案数。

那么子树中的点如果排在\(i\) 的前面就不能选,因为\(i\)必选,贡献就得减去它。

如果在后面,选了\(i\)之后也不能选它,然后组合数统计答案即可。

具体就是以每个点为根去做搜索,统计出答案之后相加即可,由于期望的线性性。

再来说说具体怎么计算答案,枚举\(y\)这棵子树的1到siz[y]的集合中前\(k\)个插入到\(i\)前面,后面的插在后面,乘上\(f_{i,j}\),在乘上选位置的方案数。

选位置的方案数就是\(C_{n + m}^{n}\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
const int MAXN = 210;
int C[MAXN][MAXN];
int siz[MAXN];
int f[MAXN][MAXN];
int lnk[MAXN];
int fac[MAXN];
const int mod = 1e9 + 7;
int cnt;
int head[MAXN << 1];
void pre() {
memset(C,0,sizeof C);
memset(fac,0,sizeof fac);
C[0][0] = 1;
fac[0] = 1;
for(int i = 1;i <= 200; ++i) {
C[i][0] = C[i][i] = 1;
fac[i] = (fac[i - 1] * i) % mod;
for(int j = 1;j <= i; ++j) {
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
}
return;
}
int T,n,x,y;
int ans;
struct edge {
int to;
int nxt;
}e[MAXN << 1];
void add(int u,int v) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
return;
} void Add(int u,int v) {
add(u,v);
add(v,u);
} void dfs(int x,int fa) {
f[x][0] = 0;f[x][1] = 1;
siz[x] = 1;
for(int i = head[x];i;i=e[i].nxt) {
int y = e[i].to;
if(y == fa) continue;
dfs(y,x);
int all_state = fac[siz[y]];
int tmp = siz[y];
int sum_state = siz[x] + siz[y];
siz[x] += siz[y];
memset(lnk,0,sizeof lnk);
for(int j = 0;j <= siz[y]; ++j,--tmp) {
all_state = (all_state + mod - f[y][j]) % mod;
for(int k = 1;k <= sum_state - siz[y]; ++k) {
lnk[j + k] = ((lnk[j + k] + all_state * f[x][k] % mod * C[j + k - 1][j] % mod * C[sum_state - j - k][tmp] % mod) % mod + mod) % mod;
}
}
for(int j = 0;j <= sum_state; ++j) {
f[x][j] = lnk[j];
}
}
}
int cas;
signed main () {
scanf("%lld",&T);
pre();
while(T--) {
scanf("%lld",&n);
memset(head,0,sizeof head);
cnt = 0;
memset(f,0,sizeof f);
memset(lnk,0,sizeof lnk);
memset(siz,0,sizeof siz);
for(int i = 1;i < n; ++i) {
scanf("%lld %lld",&x,&y);
Add(x,y);
}
ans = 0;
for(int i = 1;i <= n; ++i) {
memset(f,0,sizeof f);
dfs(i,0);
for(int j = 1;j <= n; ++j) {
ans = (ans + f[i][j]) % mod;
}
}
printf("Case #%lld: %lld\n",++cas,ans);
}
return 0;
}

ps:组合数没取模调了半天没看出来。。。

hdu 4336 Card Collector

裸.容斥原理

一坨式子懒得写了.

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define db double
int n,tmp;
db p[21];
db ans;
db sum;
void dfs(int now,db P,int st) {
if(now == tmp) {
ans += 1.0 / P;
return;
}
for(int i = st;i <= n; ++i) {
dfs(now + 1,P + p[i],i + 1);
}
}
int main () {
while(~scanf("%d",&n)) {
sum = 0;
for(int i = 1;i <= n; ++i) {
scanf("%lf",&p[i]);
sum += 1.0 / p[i];
}
for(int i = 2;i <= n; ++i) {
tmp = i;
ans = 0;
dfs(0,0,1);
//cout<<ans<<endl;
if((i & 1) == 0) {
ans = -ans;
}
sum += ans;
}
printf("%.6lf\n",sum);
}
return 0;
}

hdu 6314

容斥原理。

挖挫...这题真的是卡常数??

首先至少这种问题在高中就学过用补集去算,设\(f_{n,m}\)表示没有任何一行一列有全是黑色。

简单推一下这个就是:

\(f_{n,m} = \sum_{i = 0}^{n} \sum_{j = 0}^{m} C_{n}^{i} \times C_{m}^{j} \times (-1)^{i + j} \times 2^{(n - i) \times (m - j)}\)

答案首先就是:

\(Ans = \sum_{i = 0}^{n - A} \sum_{j = 0}^{m - B} C_{n}^{i} \times C_{m}^{j} \times f_{i,j}\)

\(\;\;\;\;\;\;\;= \sum_{i = 0}^{n - A} \sum_{j = 0}^{m - B} C_{n}^{i} \times C_{m}^{j} \sum_{u = 0}^{i} \sum_{v = 0}^{j} C_{i}^{u} \times C_{j}^{v} \times (-1)^{u + v} \times 2^{(i - u) \times (j - v)}\)

考虑哪些是可以直接处理出来的,例如这个:

\(\sum \sum C_{n}^{i} \times C_{m}^{j}\)

就可以直接算一手...

考虑后面的怎么算?

组合数展开就行了,预处理出形如\(i + j = k\)并且\(i\)的值大于等于\(l\) 的和,然后处理\(g_{i,j} = {2^{i \times j} \over i! \times j!}\)

枚举\(u,v\)即可。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
#define int long long
const int mod = 998244353;
const int MAXN = 3010;
int C[MAXN][MAXN];
int g[MAXN][MAXN];
int fac[MAXN];
int inv[MAXN];
int n,m,A,B;int ans;
int two[MAXN * MAXN];
int pow_mod(int a,int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void pre() {
fac[0] = 1;
inv[0] = 1;
two[0] = 1;
for(int i = 1;i <= MAXN * MAXN; ++i) {
two[i] = two[i - 1] * 2 % mod;
}
for(int i = 1;i <= MAXN; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = pow_mod(fac[i],mod - 2);
}
for(int i = 0;i <= 3000; ++i) {
for(int j = i;j >= 0; --j) {
C[i][j] = (((i - j) & 1 ? (mod - (inv[j] * inv[i - j] % mod)) : (inv[j] * inv[i - j] % mod)) + C[i][j + 1]) % mod;
//cout<<C[i][j]<<endl;
}
}
for(int i = 0;i <= 3000; ++i) {
for(int j = 0;j <= 3000; ++j) {
g[i][j] = two[i * j] * inv[i] % mod * inv[j] % mod;
//if(j <= 30 and i == 0) cout<<g[i][j]<<endl;
}
}
}
int cnt = 0;
//i == 1 and j == 1
signed main () {
pre();
while(~scanf("%d %d %d %d",&n,&m,&A,&B)) {
ans = 0;
for(int i = 0;i <= n - A; ++i) {
for(int j = 0;j <= m - B; ++j) {
ans = ((ans + C[n - i][A] * C[m - j][B] % mod * g[i][j] % mod) % mod + mod) % mod;
//cout<<ans<<endl;
}
}
//n : 3 m : 4 A : 1 B : 2
//cout<<g[1][1]<<endl;
//cout<<two[1]<<' '<<inv[1]<<' '<<inv[1]<<endl;
//cout<<C[2][1]<<' '<<C[3][2]<<endl;
ans = ans * fac[n] % mod * fac[m] % mod;
ans = (ans % mod + mod) % mod;
cout<<ans<<endl;
}
return 0;
}

ps:处理\(two\)数组的时候我居然乘的是2...

但是...\(AC\)不了...

卡常!

卡了三点常就过了:

  • 去掉#define int long long改为1ll * ...去算
  • int变为register int
  • 函数前面加上inline

然后呢?就过了。。。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
#define rint register int
const int mod = 998244353;
const int MAXN = 3010;
int C[MAXN][MAXN];
int g[MAXN][MAXN];
int fac[MAXN];
int inv[MAXN];
int n,m,A,B;int ans;
int two[MAXN * MAXN];
inline int pow_mod(int a,int b) {
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
inline void pre() {
fac[0] = 1;
inv[0] = 1;
two[0] = 1;
for(rint i = 1;i <= MAXN * MAXN; ++i) {
two[i] = two[i - 1] * 2 % mod;
}
for(rint i = 1;i <= MAXN; ++i) {
fac[i] = 1ll * fac[i - 1] * i % mod;
inv[i] = pow_mod(fac[i],mod - 2);
}
for(rint i = 0;i <= 3000; ++i) {
for(rint j = i;j >= 0; --j) {
C[i][j] = (((i - j) & 1 ? (mod - (1ll * inv[j] * inv[i - j] % mod)) : (1ll * inv[j] * inv[i - j] % mod)) + C[i][j + 1]) % mod;
//cout<<C[i][j]<<endl;
}
}
for(rint i = 0;i <= 3000; ++i) {
for(rint j = 0;j <= 3000; ++j) {
g[i][j] = 1ll * two[i * j] * inv[i] % mod * inv[j] % mod;
//if(j <= 30 and i == 0) cout<<g[i][j]<<endl;
}
}
}
int cnt = 0;
//i == 1 and j == 1
signed main () {
pre();
while(~scanf("%d %d %d %d",&n,&m,&A,&B)) {
ans = 0;
for(rint i = 0;i <= n - A; ++i) {
for(rint j = 0;j <= m - B; ++j) {
ans = ((ans + 1ll * C[n - i][A] * C[m - j][B] % mod * 1ll * g[i][j] % mod) % mod + mod) % mod;
//cout<<ans<<endl;
}
}
//n : 3 m : 4 A : 1 B : 2
//cout<<g[1][1]<<endl;
//cout<<two[1]<<' '<<inv[1]<<' '<<inv[1]<<endl;
//cout<<C[2][1]<<' '<<C[3][2]<<endl;
ans = ans * 1ll * fac[n] % mod * fac[m] % mod;
ans = (ans % mod + mod) % mod;
printf("%d\n",ans);
}
return 0;
}

hdu 5838

状压+容斥

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod = 772002;
const int mod = 12345678;
int cnt;
int n,m;
int cas;
int ans;
int dx[8] = {1,-1,0,0,1,-1,1,-1};
int dy[8] = {0,0,1,-1,1,1,-1,-1};
int nx[10];
int ny[10];
int f[30][1 << 10];
int sta[1 << 10];
char s[7][7];
int vis[7][7]; int ok(int x,int y) {
return x >= 0 && x < n && y >= 0 && y < m;
} int dp() {
cnt = 0;
for(int i = 0;i < n; ++i) {
for(int j = 0;j < m; ++j) {
if(s[i][j] == 'X') {
nx[cnt] = i;
ny[cnt++] = j;
}
}
}
memset(sta,0,sizeof sta);
for(int i = 0;i < (1 << cnt); ++i) {
memset(vis,0,sizeof vis);
for(int j = 0;j < cnt; ++j) {
if(~i & (1 << j)) {
for(int k = 0;k < 8; ++k) {
int Nx = nx[j] + dx[k];
int Ny = ny[j] + dy[k];
if(!ok(Nx,Ny)) continue;
vis[Nx][Ny] = 1;
}
vis[nx[j]][ny[j]] = 1;
}
} for(int j = 0;j < n; ++j) {
for(int k = 0;k < m; ++k) {
if(!vis[j][k]) {
sta[i] ++;
}
}
}
}
int all_sta = n * m;
memset(f,0,sizeof f);
f[0][0] = 1;
for(int i = 1; i <= all_sta; ++i) {
for(int j = 0;j < (1 << cnt); ++j) {
for(int k = 0;k < cnt; ++k) {
if(j & (1 << k)) {
f[i][j] = (f[i][j] + f[i - 1][j ^ (1 << k)]) % mod;
}
}
f[i][j] = ((f[i][j] + 1ll * f[i - 1][j] * max(0ll,1ll * sta[j] - i + 1) % mod) % mod + mod) % mod;
}
}
return f[all_sta][(1 << cnt) - 1];
} void dfs(int now,int lim,int f) {
if(lim == m) {
ans = ((ans + 1ll * dp() * f % mod) % mod + mod) % mod;
return;
}
else if(now == n) {
dfs(0,lim + 1,f);
return;
}
else {
dfs(now + 1,lim,f);
}
if(s[now][lim] != 'X') {
for(int j = 0;j < 8; ++j) {
int new_x = now + dx[j];
int new_y = lim + dy[j];
if(ok(new_x,new_y) && s[new_x][new_y] == 'X') goto state;
}
s[now][lim] = 'X';
dfs(now + 1,lim,-f);
s[now][lim] = '.';
state : ;
}
}
signed main () {
while(~scanf("%lld %lld",&n,&m)) {
ans = 0;
for(int i = 0;i < n; ++i) {
scanf("%s",s[i]);
}
dfs(0,0,1);
//cout<<"Case #"<<(++cas)<<':'<<' '<<(((ans % mod + mod) % mod) == m ? 0 : ((ans % mod + mod) % mod))<<endl;
cout<<((ans % mod + mod) % mod)<<endl;
}
return 0;
}
/*
2 4
.X..
...X
4 2
X.
..
..
X.
1 2
XX
*/ /*
Case #1: 2100
Case #2: 2520
Case #3: 0
*/

最新文章

  1. Andriod WIFI驱动模块
  2. Sitemesh 3 的使用及配置
  3. 安装apache服务器时遇到只能本地访问,局域网内其他电脑不能访问apache:
  4. java List&lt;Map&gt; 排序问题
  5. 删除重复&amp;海量数据
  6. gsoap创建webservice服务简单教程
  7. IOS教程视频汇总
  8. 如何设置Oracle数据库客户端字符集以及系统中的NLS_LANG环境变量
  9. 安卓websocket 封装基于Java-websocket
  10. 【java】java反射初探 ——“当类也学会照镜子”
  11. VMware安装系统时&quot;无法创建新虚拟机: 不具备执行此操作的权限&quot;的解决方案
  12. SpringMVC源码阅读:过滤器
  13. phantomjs 中如何使用xpath
  14. 可能是最早的学习Android N新特性的文章
  15. WorldWind源码剖析系列:配置载入器类ConfigurationLoader
  16. 通过socks tunnel设置http代理
  17. java.io.BufferedOutputStream 源码分析
  18. 【python基础】如何注释代码块
  19. Glide填坑指南
  20. POJ3352Road Construction(构造双连通图)sdut2506完美网络

热门文章

  1. CF 717A Festival Organization——斯特林数+递推求通项+扩域
  2. Linux编程 多进程,多线程求解PI(圆周率)
  3. 信息安全-攻击-XSS:XSS/CSS 攻击
  4. 如果遇到找不到元素如何处理? Exception in thread &quot;main&quot; org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {&quot;method&quot;:&quot;id&quot;,&quot;selector&quot;:&quot;investmentframe&quot;}
  5. CentOS7 防火墙Firewall常用命令
  6. 聊聊 API 签名方式
  7. xshell的安装及连接linux的使用方法
  8. Ajax的那点事
  9. spring注解开发:ComponentScan组件扫描
  10. win8.1安装Python提示缺失api-ms-win-crt-runtime-l1-1-0.dll问题