(相信来看这篇博客的人都有题面)

  T2以为可以线性递推,然后花了两个小时。然后想了两个小时T1,会了一个能过的算法。但是没时间写,sad.....比赛快结束时,发现T2模数$10^9+7$,内心mmp。

Problem A 生日礼物

题目大意

  给定一个$n\times m$的网格图,每个格子中有一个不是0就是1的数,要求对于任意$w\times h$的子矩阵的和都相等,问方案数。

  (为了简洁,各式子的范围请自行脑补)

  瞎推推不难发现对于一个格子$(x, y)$,满足$a_{x, y} + a_{x + w, y + h} = a_{x + w, y} + a_{x, y + h}$。

  移项得:

$\begin{align}a_{x, y} - a_{x + w, y} = a_{x, y + h} - a_{x + w, y + h}\end{align}$

  用归纳法能够得出对于每连续的$w + 1$行,对模$h$的剩余相同的列,这$w + 1$行中的第一行和最后一行的上的数之差相等。

  对于上图来说就是$a - b = c - d = e - f$。

  考虑先确定前$w$行,每次在后面添加一行。显然这一行我们只用考虑前$h$个数(剩下的用式$(1)$来确定)。

  考虑每一处$(i, j)$和它上面第$w$个格子上的数的差$d$

  • 若$d = 1$,则说明$a_{i - w, j + kh} = 0 (k = 0, 1, \dots)$
  • 若$d = 0$,则什么都不能说明
  • 若$d = -1$,则说明$a_{i - w, j + kh} = 1 (k = 0, 1, \dots)$

  所以变化量能为$1,-1$的只有当这一行上纵坐标模$h$同余于它的位置上的数等于它。

  然后发现只要确定左上角的$w\times h$的矩形的状况,剩下的就能用快速幂计算。

  然后我的做法就比较沙雕了。

  $f_{s}$表示恰好包含$s$中的位置作为横着相同的格子,且将前$w$行填满的方案数。(不考虑这些格子上的数)

  这个首先需要考虑这些格子上的数,进行容斥和子集和变换,再将这些格子上的数的贡献减去。

  然后单独考虑这个矩阵中每一行的贡献,枚举$0$和$1$的数量,就可以计算贡献了。

Code

 #include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef bool boolean; const int Mod = 1e9 + ; int add(int a, int b) {
return ((a += b) >= Mod) ? (a - Mod) : (a);
} int sub(int a, int b) {
return ((a -= b) < ) ? (a + Mod) : (a);
} int mul(int a, int b) {
return a * 1ll * b % Mod;
} int qpow(int a, int p) {
int rt = , pa = a;
for ( ; p; p >>= , pa = mul(pa, pa))
if (p & )
rt = mul(rt, pa);
return rt;
} const int S = << ; int n, m, w, h;
int f[S], bit[S];
int c[][], sc[][];
int d[][], sd[][];
int comb[][] = {{, , , , }, {, , , , }, {, , , , }, {, , , , }, {, , , , }};
int invs[]; inline void init() {
scanf("%d%d%d%d", &n, &m, &w, &h);
} int getline(int s, int l) {
int rt = (s >> l) & ;
for (int i = ; i < w; i++)
rt = (((s >> (h * i + l)) & ) << i) | rt;
return rt;
} int getrow(int s, int row) {
int msk = ( << h) - ;
return s >> (h * row) & msk;
} inline void solve() {
d[][] = ;
for (int i = ; i < ; i++)
for (int j = ; j <= i; j++) {
d[i + ][j] = add(d[i + ][j], d[i][j]);
d[i + ][j + ] = add(d[i + ][j + ], d[i][j]);
} int sl_repeat = m / h;
for (int i = ; i <= ; i++)
for (int j = ; j <= i; j++)
sd[i][j] = qpow(d[i][j], sl_repeat); bit[] = ;
for (int i = ; i < S; i++)
bit[i] = bit[i >> ] + (i & ); int all = << (w * h);
for (int s = ; s < all; s++) {
f[s] = ( << bit[s]);
for (int l = ; l < h; l++) {
int sl = getline(s, l);
int blank = w - bit[sl];
int cmp = ;
boolean aflag = ((m % h) > l);
for (int i = ; i <= blank; i++)
cmp = add(mul(sd[blank][i], (aflag) ? (d[blank][i]) : ()), cmp);
f[s] = mul(f[s], cmp);
}
} int size = w * h;
for (int i = ; i < size; i++)
for (int j = ; j < all; j++)
if (!((j >> i) & ))
f[j] = sub(f[j], f[j ^ ( << i)]); for (int k = ; k <= ; k++)
for (int c0 = ; c0 <= k; c0++) {
int c1 = k - c0, ava = min(c0, c1);
int& res = c[c0][c1];
for (int use = ; use <= ava; use++) {
// res = add(res, mul(comb[c0][use], mul(comb[c1][use], fac[use])));
res = add(res, mul(comb[c0][use], comb[c1][use]));
}
sc[c0][c1] = qpow(res, n / w - );
} invs[] = ;
for (int i = ; i <= ; i++)
invs[i] = qpow( << i, Mod - );
for (int i = ; i < all; i++)
f[i] = mul(f[i], invs[bit[i]]); int res = ;
for (int s = ; s < all; s++) {
if (!f[s])
continue;
int tmp = ;
for (int r = ; r < w; r++) {
int sr = getrow(s, r);
int spe = bit[sr], cmp = ;
boolean aflag = ((n % w) > r);
for (int c0 = ; c0 <= spe; c0++) {
cmp = add(cmp, mul(mul(::sc[c0][spe - c0], ((aflag) ? (c[c0][spe - c0]) : ())), comb[spe][c0]));
}
tmp = mul(tmp, cmp);
// cerr << sr << " " << s << " " << r << " " << cmp << '\n';
}
// if (tmp && f[s])
// cerr << s << " " << mul(f[s], tmp) << '\n';
res = add(res, mul(f[s], tmp));
}
printf("%d\n", res);
} int main() {
init();
solve();
return ;
}

Problem A

Problem B 咕咕

题目大意

  有$n$种物品,每种物品无限个,第$i$种物品的体积为$a_i$。设$f(n)$表示恰好填满容量为$n$的背包的方案数,求$\sum_{i = L}^{R}f(i)$。

  (这道题的名称告诉了我们不想掉rating的正确做法)

  (我们可以线性递推 + 三模数NTT)

  考虑每加入一个物品相当于对模$a_i$同余于$j\ (j = 0, 1, \dots, a_i - 1)$的地方分别做一次前缀和。

  所以对于模$[a_{1}, a_{2}, \cdots, a_{n}]$余$r$的地方可以用一个$n - 1$次多项式表示。

  由于要求前缀和,就再加入体积为$1$的物品。

  对于$L-1,R$处的取值直接用$Lagrange$插值。

Code

 #include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef bool boolean; #define ll long long const int N = , S = * N;
const int Mod = 1e9 + ; int add(int a, int b) {
return ((a += b) >= Mod) ? (a - Mod) : (a);
} int sub(int a, int b) {
return ((a -= b) < ) ? (a + Mod) : (a);
} int mul(int a, int b) {
return a * 1ll * b % Mod;;
} void exgcd(int a, int b, int& x, int& y) {
if (!b)
x = , y = ;
else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < ) ? (x + n) : (x);
} int n, prod = , m;
int a[N], f[S]; inline void init() {
scanf("%d", &n);
for (int i = ; i < n; i++)
scanf("%d", a + i), prod *= a[i];
m = prod * (n + );
f[] = ;
for (int j = ; j < n; j++)
for (int i = ; i <= m; i++)
if (a[j] <= i)
f[i] = add(f[i - a[j]], f[i]);
for (int i = ; i <= m; i++)
f[i] = add(f[i], f[i - ]);
} int Lagrange(ll _x) {
if (_x <= m)
return f[_x];
int k = _x % prod;
int x = (_x / prod) % Mod;
int rt = ;
for (int i = ; i <= n; i++) {
int tmp = f[i * prod + k];
for (int j = ; j <= n; j++)
if (i ^ j)
tmp = mul(tmp, mul(sub(x, j), inv(sub(i, j), Mod)));
rt = add(rt, tmp);
}
return rt;
} ll l, r;
inline void solve() {
scanf("%lld%lld", &l, &r);
printf("%d\n", sub(Lagrange(r), Lagrange(l - )));
} int main() {
init();
solve();
return ;
}

Problem B

Problem C 解决npc

题目大意

  要求构造一个点数不超过$50$,边数不超过$100$的有向图,使得它的本质不同的拓扑序的个数为$x$。

  当$x = 1,2$的时候特判。

  当$x$不大的时候,构造一条链和一个点就行了。

  当$x$比较大的时候,考虑这样一个东西:

  考虑在加入紫色节点前,以红色节点结尾的拓扑序的个数为$x$,以绿色节点结尾的拓扑序的个数为$y$,如图所示加入紫色节点,那么不难得到以紫色节点为结尾的拓扑序有$x + y$个。

  那么就可以直接爆搜了。

Code

 #include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
typedef bool boolean; #define pii pair<int, int> const int Lim = ; int X; inline void init() {
scanf("%d", &X);
} int type[Lim + ];
vector<pii> E;
void dfs(int x, int y, int d, int lim) {
if (d == lim || d == Lim || x + y > X)
return;
if (x + y == X) {
vector<int> L(), R();
L[] = , L[] = , R[] = , R[] = ;
E.push_back(pii(, ));
E.push_back(pii(, ));
E.push_back(pii(, ));
for (int i = ; i < d; i++)
if (!type[i]) {
E.push_back(pii(L.back(), i));
E.push_back(pii(R[R.size() - ], i));
L.push_back(i);
} else {
E.push_back(pii(R.back(), i));
E.push_back(pii(L[L.size() - ], i));
R.push_back(i);
} printf("%d %d\n", d, (signed) E.size());
for (int i = ; i < (signed) E.size(); i++)
printf("%d %d\n", E[i].first, E[i].second);
exit();
} type[d] = ;
dfs(x + y, y, d + , lim);
type[d] = ;
dfs(x, x + y, d + , lim);
} inline void solve() {
if (X == ) {
printf("2 1\n0 1\n");
} else if (X == ) {
printf("3 2\n0 1\n2 1\n");
}else if (X <= ) {
printf("%d %d\n", X, X - );
for (int i = ; i < X - ; i++)
printf("%d %d\n", i, i + );
} else {
for (int lim = ; lim <= ; lim++)
dfs(, , , lim);
puts("Failed");
}
} int main() {
init();
solve();
return ;
}

Problem C

2018年山东省省队集训 Round 1 Day 2简要题解的更多相关文章

  1. Codeforces Round #557 (Div. 1) 简要题解

    Codeforces Round #557 (Div. 1) 简要题解 codeforces A. Hide and Seek 枚举起始位置\(a\),如果\(a\)未在序列中出现,则对答案有\(2\ ...

  2. Codeforces Round #545 (Div. 1) 简要题解

    这里没有翻译 Codeforces Round #545 (Div. 1) T1 对于每行每列分别离散化,求出大于这个位置的数字的个数即可. # include <bits/stdc++.h&g ...

  3. Codeforces Round #398 (div.2)简要题解

    这场cf时间特别好,周六下午,于是就打了打(谁叫我永远1800上不去div1) 比以前div2的题目更均衡了,没有太简单和太难的...好像B题难度高了很多,然后卡了很多人. 然后我最后做了四题,E题感 ...

  4. Codeforces Round #483 (Div. 1) 简要题解

    来自FallDream的博客,未经允许,请勿转载,谢谢. 为了证明一下我又来更新了,写一篇简要的题解吧. 这场比赛好像有点神奇,E题莫名是道原题,导致有很多选手直接过掉了(Claris 表演24s过题 ...

  5. Codeforces Round #535(div 3) 简要题解

    Problem A. Two distinct points [题解] 显然 , 当l1不等于r2时 , (l1 , r2)是一组解 否则 , (l1 , l2)是一组合法的解 时间复杂度 : O(1 ...

  6. Codeforces Round #498 (Div. 3) 简要题解

    [比赛链接] https://codeforces.com/contest/1006 [题解] Problem A. Adjacent Replacements        [算法] 将序列中的所有 ...

  7. Codeforces Round #588 (Div. 1) 简要题解

    1. 1229A Marcin and Training Camp 大意: 给定$n$个对$(a_i,b_i)$, 要求选出一个集合, 使得不存在一个元素好于集合中其他所有元素. 若$a_i$的二进制 ...

  8. Codeforces Round #576 (Div. 1) 简要题解 (CDEF)

    1198 C Matching vs Independent Set 大意: 给定$3n$个点的无向图, 求构造$n$条边的匹配, 或$n$个点的独立集. 假设已经构造出$x$条边的匹配, 那么剩余$ ...

  9. [题解][Codeforces]Codeforces Round #602 (Div. 1) 简要题解

    orz djq_cpp lgm A 题意 给定一个分别含有 \(\frac n2\) 个左括号和右括号的括号序列 每次可以将序列的一个区间翻转 求一个不超过 \(n\) 次的操作方案,使得操作完之后的 ...

随机推荐

  1. fiddler修改Requests之前的数据和response 之后的数据

    1. 开启抓包 file--->capture traffic 2. 在页面底部黑框输入bpu http://www.runoob.com/?s=mysql 3. 在浏览器URL输入http:/ ...

  2. 你应当如何学习C++以及编程(细节是必要的,但不是重要的,把时间用在集中精力去解决问题,而不是学习新技术,那样练不成高手。在实践中提高才是最重要的。最最重要的内功还是长期学习所磨练出来的自学能力)good

    最近在学习Qt但由于没有C++的基础,感觉学的很吃力.看到pongba的这篇文章感觉不错就弄过来了, 原文地址:http://blog.csdn.net/qter_wd007/article/deta ...

  3. 聚合函数对NULL统计

    Table ID Amount Number 1 28.26 NULL 2 NULL NULL 3 NULL NULL SQL SELECT SUM(Amount),SUM(Number),COUNT ...

  4. windows共享文件夹至centos系统文件夹下

    1. window 共享文件夹 https://jingyan.baidu.com/article/358570f6633ba4ce4624fc48.html 2. 在访问Windows共享资料之前, ...

  5. 初尝Spring Cloud Config

    1,下载源码 地址https://spring.io/guides/gs/centralized-configuration/ 2,导入工程 解压后分别把Server端与Client端导入到两个Ecl ...

  6. table添加正确的样式

    以前在做表格的时候,会在表格<table>标签中添加一些属性,来改变表格的样式,经常用到的有这几个 width 表格的宽度border 表格边框的宽度cellpadding  单元边沿与其 ...

  7. python项目推荐(转载知乎)

    作者:Wayne Shi链接:https://www.zhihu.com/question/29372574/answer/88744491来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  8. Sql题面试题

    哪位大神会此题,请给出答案,十分感谢! 哪位大神会此题,请给出答案,十分感谢!

  9. React-typescript-antd 常见问题

    一.The key 'Accept' is not sorted alphabetically //tslint.json { "extends": ["tslint:r ...

  10. C# 字段和属性

    最大的疑惑就是:有了字段,为什么还要有属性呢? 如果在一个类中有一个公有字段,那么在这个类的外部我们可以自由无阻的使用这个字段,但是如果给这个字段赋了一个很“离谱”的值,那这对程序可能会造成很大的影响 ...