ZROI week3
作业
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
*/
ZROI week3的更多相关文章
- 个人作业-Week3
个人作业-Week3 1. 软件工程师的成长 同学们在上这门课的时候,还是大三,你的困难和迷茫,别人一定有过.请看看别人怎么学习的,有些是科班,有些是野路子,有些成功,有些失败. 请读完下面所有博客( ...
- Spark小课堂Week3 FirstSparkApp(Dataframe开发)
Spark小课堂Week3 FirstSparkApp(代码优化) RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lamb ...
- Spark小课堂Week3 FirstSparkApp(RDD开发)
Spark小课堂Week3 FirstSparkApp 问题:Java有哪些数据结构 大致有如下几种,其中List与Map是最重要的: List Map Set Array Heap Stack Qu ...
- Deep Learning--week1~week3
week1 一张图片,设像素为64*64, 颜色通道为红蓝绿三通道,则对应3个64*64实数矩阵 为了用向量表示这些矩阵,将这些矩阵的像素值展开为一个向量x作为算法的输入 从红色到绿色再到蓝色,依次按 ...
- 20165214 2018-2019-2 《网络对抗技术》Exp1 PC平台逆向破解 Week3
<网络对抗技术>Exp1 PC平台逆向破解之"逆向及Bof基础实践说明" Week3 一. 实验预习 1.什么是漏洞?漏洞有什么危害? 漏洞就是在计算机硬件.软件.协议 ...
- 个人作业Week3
个人作业week3 一. 调研,评测 1.我的使用体验 版本:IOS版 BUG_1: 点击单词本中的“同步”后,会提示登录Microsoft账户.登录成功立即开始同步单词本.在单词本同步过程中, ...
- Week3 关于“微软必应词典客户端”的案例分析
第一部分 调研,评测 一.iphone客户端的bug挖掘: 1.在例句中点击单词或短语,如果这个时候点得稍微快了一点,关联相应的翻译时会出现混乱. 经过调查发现,这个bug应该是必应得一个全平台错误 ...
- [BUAA_SE_2017]案例分析-Week3
Week3 案例分析 一.调研评测 案例: 神策数据的数据概览功能 Demo: 电商类产品Demo 评价: d) 好,不错 个人评价:神策数据电商类产品Demo的数据概览功能是相当不错的.首先点击进入 ...
- 20165310 NstSec2019 Week3 Exp1 逆向与Bof基础
20165310 NstSec2019 Week3 Exp1 逆向与Bof基础 一.实验内容 实验目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用fo ...
随机推荐
- (转)使用InfluxDB+cAdvisor+Grafana配置Docker监控
文档来源 文档来源:How to setup Docker Monitoring 由garyond翻译.校正及整理 Docker监控简介 我们提供的Docker主机和容器越来越多,对Docker服务器 ...
- idea中git回退远程仓库版本
工作中遇到,代码已提交并已提交到远程仓库,现需要回退到之前版本,记录如下: 记录当前版本的版本号和需要回退到版本的版本号. current version:85e7f32dfe421c5892a4e2 ...
- left join right inner join 区别
连表查询 select a, b, c from table_a tb_a left (right) join table_b tb_b on tb_a.id = tb_b.id left : tab ...
- mysql + grafana监控
1.首先需要增加授权 CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'XXXXXXXX' WITH MAX_USER_CONNECTIONS 3 ...
- [USACO 07NOV]电话线Telephone Wire
题目描述 Farmer John's cows are getting restless about their poor telephone service; they want FJ to rep ...
- C语言|博客作业6
一.本周教学内容&目标 第3章 分支结构 3.1-3.2 使学生熟悉多分支结构.字符型数据类型和逻辑运算符. 二.本周作业头 问题 答案 这个作业属于那个课程 C语言程序设计II 这个作业要求 ...
- [Fw]中断的初始化
要使用中断肯定得初始化,这些初始化在系统启动时已经为你做好了,但是我们还是来看看怎样初始化的,这样就能更好的理解中断机制了.先看下面函数: 355 void __init init_ISA_irqs ...
- 三、Json方式函数
一.Json方式函数 // 4. 查看对象信息 console.dir(obj) =>可以显示一个对象所有的属性和方法. var info = { blog: "http://cllg ...
- openssl部分解读
前言 openssl是个开源的加密库.可以对文件进行加密解密. 小知识 术语: 单词: Encryption 加密 Decryption 解密 ssl 安全socket层 tsl 最 ...
- 虚拟机设置静态IP地址
前言 NAT连接方式只能配置一次,配置好子网掩码和网关IP后,虚拟机NAT连接的ip段都是同一个ip段 1.菜单栏选择 编辑 -> 虚拟网络编辑器,打开虚拟网络编辑器对话框,选择Vmnet8 N ...