3.10考试总结
话说最近感觉越来越喜欢压行了qaq
A 概率好题
题意:51nod 1667
题解:咕咕咕
B lyk与gcd
题意:51nod 1678
题解:容斥
所求等于所有的和减去不与 i 互质的和
直接将 i 质因数分解,不用管次数(比如说4算了贡献,那这份贡献肯定2里面也有,所以不用算4)
然后容斥出这个和
比如\(val(60)=val(2)+val(3)+val(5)-val(2,3)-val(2,5)-val(3,5)+val(2,3,5)\)
然后就维护一个\(val\)数组,使得\(val[i]\)表示以所有质因数含有 i 作为下标的原数组的和
于是\(val(2,3)==val[6]\)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 100005
#define int long long
int a[maxn], n, q;
vector<int> ve;
int val[maxn], sum;
inline void fac(int x)
{
ve.clear();
for (int i = 2; i * i <= x; ++i)
if (x % i == 0)
{
ve.push_back(i);
while (x % i == 0) x /= i;
}
if (x != 1) ve.push_back(x);
}
inline int query(int x)
{
fac(x);
int ans = 0, len = ve.size();
for (int i = 1; i < (1 << len); ++i)
{
int cnt = 0, tp = 1;
for (int j = 0; j < len; ++j)
if (i & (1 << j)) ++cnt, tp *= ve[j];
if (cnt & 1) ans += val[tp];
else ans -= val[tp];
}
return ans;
}
inline void update(int pos, int v)
{
sum += v - a[pos];
for (int i = 1; i * i <= pos; ++i)
if (pos % i == 0)
{
val[i] += v - a[pos];
if (i * i != pos) val[pos / i] += v - a[pos];
}
a[pos] = v;
}
signed main()
{
read(n), read(q);
for (int i = 1; i <= n; ++i) read(a[i]), sum += a[i];
for (int i = 1; i <= n; ++i)
for (int j = 1; i * j <= n; ++j) val[i] += a[i * j];
for (int i = 1, op, x, y; i <= q; ++i)
{
read(op), read(x);
if (op == 1) read(y), update(x, y);
else printf("%lld\n", sum - query(x));
}
return 0;
}
C 高楼和棋子
题意:51nod 1306
题解:dp
设\(dp[i][j]\)表示有 i 个棋子,试 j 次最多能试出来的最高楼层
于是每一个询问二分一下即可
注意1或2个棋子时要特判(因为状态数是\(\sqrt[i]{10^{18}}\)这个级别的)
注意要开vector,以及inf要开大一点
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define ll long long
#define maxnum 2000000
ll n, m;
vector<ll> dp[65];
int main()
{
int T; read(T);
for (int i = 0; i <= maxnum; ++i)
dp[0].push_back(0);
for (int i = 1; i <= 64; ++i)
{
dp[i].push_back(0);
for (int j = 1; j <= maxnum; ++j)
{
dp[i].push_back(dp[i - 1][j - 1] + dp[i][j - 1] + 1);
if (dp[i][j] > 1e18) break;
}
}
while (T--)
{
read(n), read(m);
if (m == 1) printf("%lld\n", n);
else if (m == 2)
{
long long tp = sqrt(2 * n);
if (tp * (tp + 1) < 2 * n) ++tp;
printf("%lld\n", tp);
}
else printf("%d\n", (int)(lower_bound(dp[m].begin(), dp[m].end(), n) - dp[m].begin()));
}
return 0;
}
D 大大走格子
题意:51nod 1468
题解:容斥+dp
把障碍点按y排序,依次从前面递推,容斥一下即可
#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 200005
#define P 1000000007
#define ll long long
struct Node
{
int x, y;
bool operator < (const Node& p) const { if (y != p.y) return y < p.y; return x < p.x; }
}node[maxn];
ll ans[maxn], fac[maxn], inv[maxn];
inline ll qpow(ll x, ll y)
{
ll ans = 1;
while (y) { if (y & 1) ans = ans * x % P; x = x * x % P; y >>= 1; }
return ans;
}
inline ll C(int x, int y) { return fac[x] * inv[y] % P * inv[x - y] % P; }
int main()
{
int h, w, n, tp;
read(h), read(w), read(n), tp = max(h, w) * 2;
fac[0] = inv[0] = 1;
for (int i = 1; i <= n; ++i)
read(node[i].x), read(node[i].y), --node[i].x, --node[i].y;
for (int i = 1; i <= tp; ++i) fac[i] = fac[i - 1] * i % P;
inv[tp] = qpow(fac[tp], P - 2);
for (int i = tp - 1; i; --i) inv[i] = inv[i + 1] * (i + 1) % P;
node[++n] = { h - 1,w - 1 };
sort(node + 1, node + n + 1);
for (int i = 1; i <= n; ++i)
{
#define X node[i].x
#define Y node[i].y
ans[i] = C(X + Y, X);//从起点走到这个点
for (int j = 1; j < i; ++j)//从前一个障碍点走到这个点
{
if (node[j].x > X || node[j].y > Y) continue;
ans[i] = ans[i] - ans[j] * C(X - node[j].x + Y - node[j].y, X - node[j].x) % P;
ans[i] %= P;
}
ans[i] = (ans[i] + P) % P;
}
printf("%lld\n", ans[n]);
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.