T1
数据范围很合适..
第一档就是暴力枚举
第二档就是数位DP
第三档就是矩阵乘法
丢一下学长的博客
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
LL n;
const int mod = 1e9 + 7;
struct ju
{
LL c[4][4];
friend ju operator *(const ju &a, const ju &b)
{
ju c;
memset(c.c, 0, sizeof(c.c));
for (int i = 1; i <= 3; ++i)
for (int j = 1; j <= 3; ++j)
for (int k = 1; k <= 3; ++k)
c.c[i][j] += a.c[i][k] * b.c[k][j] % mod, c.c[i][j] %= mod;
return c;
}
} base, ans;
LL ksm(LL a, LL b, LL mod)
{
LL res = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1)res = res * a % mod;
return res;
}
ju ksm(ju a, LL b)
{
ju res;
memset(res.c, 0, sizeof(res.c));
for (int i = 1; i <= 3; ++i)res.c[i][i] = 1;
for (; b; b >>= 1, a = a * a)
if (b & 1)res = res * a;
return res;
}
int main()
{
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
cin >> n;
base.c[1][1] = 3; base.c[1][2] = 2; base.c[1][3] = 0;
base.c[2][1] = 1; base.c[2][2] = 3; base.c[2][3] = 1;
base.c[3][1] = 0; base.c[3][2] = 2; base.c[3][3] = 3;
ans .c[1][1] = 3;
ans .c[2][1] = 1;
ans .c[3][1] = 0;
ans = ksm(base, n - 1) * ans;
(((ans.c[1][1] -= ksm(2, n, mod) + ksm(4, n, mod) % mod) %= mod) += mod) %= mod;
ans.c[1][1] += ksm(3, n, mod);
cout << ans.c[1][1] % mod;
fclose(stdin); fclose(stdout);
return 0;
}
T2
发现一个位置的值是奇数当且仅当 它所在的行加的次数+它所在的列加的次数 的和是奇数。
当有x行加了奇数次,y列加了奇数次,那么奇数个数就是(n-x)y+x(m-y)
枚举x,可以解方程得到y,特判一下(2x==n&&xm==k)的情况(化一化式子就知道了),贡献就是\(\displaystyle C_n^xC_m^yC_{\frac{r-x}{2}+n-1}^{n-1}C_{\frac{c-y}{2}+m-1}^{m-1}\)
大力卡一卡边界就行了。
#include<iostream>
#include<cstdio>
#define int long long
#define LL long long
#define DB double
using namespace std;
LL n, m, r, c, k, ans;
const int N = 400010, M = 200000, mod = 1e9 + 7;
LL jc[N], inv[N];
inline int read()
{
int res = 0; char ch = getchar(); bool XX = false;
for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
return XX ? -res : res;
}
LL ksm(LL a, LL b, LL mod)
{
LL res = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1)res = res * a % mod;
return res;
}
void YYCH()
{
jc[0] = jc[1] = inv[0] = inv[1] = 1;
for (int i = 2; i <= M; ++i)jc[i] = jc[i - 1] * i % mod;
inv[M] = ksm(jc[M], mod - 2, mod);
for (int i = M - 1; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
}
LL C(LL n, LL m) {if (n < m)return 0; return jc[n] * inv[m] % mod * inv[n - m] % mod;}
void suan(LL x, LL y)
{
if (((r - x) & 1) || ((c - y) & 1))return;
ans += C(n, x) * C(m, y) % mod * C(((r - x) >> 1) + n - 1, n - 1) % mod * C(((c - y) >> 1) + m - 1, m - 1) % mod, ans %= mod;
}
DB jue(DB x) {return x > 0 ? x : -x;}
int zheng(DB x)
{
return jue(x - (int)x) < 1e-3;
}
signed main()
{
freopen("matrix.in", "r", stdin);
freopen("matrix.out", "w", stdout);
cin >> n >> m >> r >> c >> k;
YYCH();
for (int x = (r & 1); x <= n; x += 2)
{
if (n == 2 * x)
{
if (x * m == k) for (int y = (c & 1); y <= m; y += 2)suan(x, y);
}
else
{
DB y = (DB)(k - x * m) / (n - 2 * x);
if ((int)y < 0 || !zheng(y))continue;
suan(x, y);
}
}
cout << ans;
fclose(stdin); fclose(stdout);
return 0;
}
T3
前置题目线段树做法
首先离线...
原来的题目限制的只有自己这个位置,现在变成了它及它前边的k个位置。
线段树维护 区间取min,单点查询 即可。
考场上没开大空间直接凉凉...
好像这道题莫队跑得挺快的。
#include<algorithm>
#include<iostream>
#include<cstdio>
#define lson (k<<1)
#define rson ((k<<1)|1)
#define LL long long
#define DB double
using namespace std;
int n, m, q, k;
const int N = 400010, inf = 1e9;
int vis[N], a[N], ans[N], to[N][11], las[N], tr[N << 2], lz[N << 2];
struct Ask {int l, r, ans, id;} Q[N];
int my1(const Ask &a, const Ask &b) {return a.l < b.l;}
int my2(const Ask &a, const Ask &b) {return a.id < b.id;}
inline int read()
{
int res = 0; char ch = getchar(); bool XX = false;
for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
return XX ? -res : res;
}
void Write(int x, int opt)
{
if (opt && !x)putchar('0');
if (!x)return; Write(x / 10, 0);
putchar((x - x / 10 * 10) + '0');
}
void build(int k, int l, int r)
{
lz[k] = inf;
if (l == r)
{
tr[k] = ans[l];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
}
inline void cd(int k)
{
lz[lson] = min(lz[lson], lz[k]); lz[rson] = min(lz[rson], lz[k]);
lz[k] = inf;
}
void change(int k, int l, int r, int x, int y, int v)
{
if (x <= l && r <= y)
{
lz[k] = min(lz[k], v);
return;
}
if (lz[k] != inf)cd(k);
int mid = (l + r) >> 1;
if (x <= mid)change(lson, l, mid, x, y, v);
if (mid + 1 <= y)change(rson, mid + 1, r, x, y, v);
}
int ask(int k, int l, int r, int pos)
{
if (l == r)
{
return min(lz[k], tr[k]);
}
if (lz[k] != inf)cd(k);
int mid = (l + r) >> 1;
if (pos <= mid)return ask(lson, l, mid, pos);
else return ask(rson, mid + 1, r, pos);
}
inline void solve2()
{
for (int i = 1; i <= q; ++i)
{
Q[i].l = read(); Q[i].r = read(); Q[i].id = i;
}
sort(Q + 1, Q + 1 + q, my1);
int now = 1;
for (int i = 1; i <= m; ++i)
{
for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j)
{
vis[j] = 1;
to[las[j]][a[las[j]] - j] = i;
las[j] = i;
}
while (vis[now])++now;
ans[i] = now;
}
for (int i = 1; i <= n; ++i)to[las[i]][a[las[i]] - i] = m + 1;
build(1, 1, m);
now = 1; int pos;
for (int i = 1; i <= m; ++i)
{
while (Q[now].l == i)
{
Q[now].ans = ask(1, 1, m, Q[now].r);
++now;
}
for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j)
{
pos = to[i][a[i] - j] - 1;
change(1, 1, m, i, pos, j);
}
}
sort(Q + 1, Q + 1 + q, my2);
for (int i = 1; i <= q; ++i)
{
if (Q[i].ans > n - k + 1)puts("-1");
else Write(Q[i].ans, 1), putchar('\n');
}
}
int main()
{
freopen("stall.in", "r", stdin);
freopen("stall.out", "w", stdout);
cin >> n >> m >> q >> k;
for (int i = 1; i <= m; ++i)a[i] = read();
solve2();
fclose(stdin); fclose(stdout);
return 0;
}
任何时候,都不要自信到连暴力分都不要。