静下心 做自己能控制的事情
加油
周一
Master of Sequence(推公式 + 数学)
这道题主要是推公式
同时ai <= 1000是突破口,说明很多ai是重复的,可以记录出现次数,然后遍历1到1000
把这个向下取整的式子分离出两个式子
t / ai b / ai 同时看什么时候会多减一个一
不用推,感性一样其实就比较多出来的t % a 和 b % a就可以了
显然如果相减大于等于0,向下取整是0,没有影响
如果小于0,向下取整会多减去一个1
所以我们处理三个部分
第一部分t / ai
可以因为ai <= 1000 可以直接从1遍历一千结合出现次数来处理
第二部分bi / ai 可以O(1)维护
第三部分t % ai 和bi % ai
显然维护bi % ai 然后for1到1000
那么可以开1000个树状数组维护ti % ai,因为是单点修改,区间求和
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int M = 1e3 + 10;
const int N = 1e5 + 10;
int a[N], b[N], f[M][M], num[M], n, m;
ll sum;
int lowbit(int x) { return x & -x; }
void add(int x, int p, int id)
{
x++;
for(; x <= 1000; x += lowbit(x))
f[id][x] += p;
}
int ask(int x, int id)
{
x++;
int res = 0;
for(; x; x -= lowbit(x))
res += f[id][x];
return res;
}
bool check(ll t, ll k)
{
ll res = -sum;
_for(i, 1, 1000)
res += t / i * num[i] - num[i] + ask(t % i, i);
return res >= k;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
sum = 0;
memset(num, 0, sizeof num);
memset(f, 0, sizeof f);
scanf("%d%d", &n, &m);
_for(i, 1, n) scanf("%d", &a[i]), num[a[i]]++;
_for(i, 1, n)
{
scanf("%d", &b[i]);
sum += b[i] / a[i];
add(b[i] % a[i], 1, a[i]);
}
while(m--)
{
int op, x, y, k;
scanf("%d", &op);
if(op <= 2)
{
scanf("%d%d", &x, &y);
num[a[x]]--;
sum -= b[x] / a[x];
add(b[x] % a[x], -1, a[x]);
if(op == 1) a[x] = y;
else b[x] = y;
num[a[x]]++;
sum += b[x] / a[x];
add(b[x] % a[x], 1, a[x]);
}
else
{
scanf("%d", &k);
ll l = 0, r = 1e12;
while(l + 1 < r)
{
ll m = l + r >> 1;
if(check(m, k)) r = m;
else l = m;
}
printf("%lld\n", r);
}
}
}
return 0;
}
Master of Phi(数论)
用到了挺多的数论知识
积性函数,迪利克雷卷积,欧拉函数通项公式
推出公式这道题就做完了
周二
C. Choosing flowers(思维)
这道题妙啊
关键是发现最优策略一定符合某种性质
显然策略是一些不选,一些选一个,一些选大于1个
首先如果是全部选一个的,那就直接排序了
如果有选大于1个的,可以发现,所有的bi,可以全部选最优的
那么其实这种情况下只有一种花选了bi,其他都是选一个
那就直接枚举那一种花选了bi就可以了,首先先贪心,把大于bi的ai全部都选了,这个过程可以给ai排序然后二分找位置,前缀和。 之后再选当前的ai,再选bi
注意当前的ai可能在前面已选的ai里面,也可能不在,这个细节要判断一下
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int a[N], b[N], c[N], n, m;
ll s[N];
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
_for(i, 1, m)
{
scanf("%d%d", &a[i], &b[i]);
c[i] = a[i];
}
sort(c + 1, c + m + 1, greater<int>());
_for(i, 1, m) s[i] = s[i - 1] + c[i];
ll ans = 0;
if(n <= m) ans = s[n];
_for(i, 1, m)
{
int pos = upper_bound(c + 1, c + m + 1, b[i], greater<int>()) - c - 1;
if(n <= pos) continue;
ll res = s[pos], cnt = n - pos;
if(a[i] <= b[i]) res += a[i], cnt--;
res += cnt * b[i];
ans = max(ans, res);
}
printf("%lld\n", ans);
}
return 0;
}
周三
D. 505(思维 + 状压dp)
自己想的时候发现了4 乘4以上肯定不行
但是没有注意到,如果可以的话,n只有1,2, 3三种取值……
没有利用好这个信息
知道这个后,n=1为0
n=2的话,就是每一个列一的个数为奇偶奇偶……或者偶奇偶奇……
n=3的话状压dp就好了,挺简单的一个状压dp
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int a[N], dp[N][8], n, m;
int id(int i, int j) { return (i - 1) * m + j; }
bool check(int pre, int now)
{
int k[5][5];
k[1][1] = pre & 1; k[2][1] = (pre >> 1) & 1; k[3][1] = (pre >> 2) & 1;
k[1][2] = now & 1; k[2][2] = (now >> 1) & 1; k[3][2] = (now >> 2) & 1;
int cnt1 = k[1][1] + k[1][2] + k[2][1] + k[2][2];
int cnt2 = k[2][1] + k[2][2] + k[3][1] + k[3][2];
return (cnt1 & 1) && (cnt2 & 1);
}
int cal(int now, int j)
{
int res = 0, t[5];
t[1] = now & 1; t[2] = (now >> 1) & 1; t[3] = (now >> 2) & 1;
_for(i, 1, 3) res += (t[i] != a[id(i, j)]);
return res;
}
int main()
{
scanf("%d%d", &n, &m);
if(n > m) swap(n, m);
_for(i, 1, n)
_for(j, 1, m)
scanf("%1d", &a[id(i, j)]);
if(n >= 4) puts("-1");
else if(n == 1) puts("0");
else if(n == 2)
{
int ans = 0, cnt = 0, t = 0;
_for(j, 1, m)
{
int one = (a[id(1, j)] + a[id(2, j)]) % 2;
cnt += (one != t);
t ^= 1;
}
ans = max(ans, cnt);
t = 1; cnt = 0;
_for(j, 1, m)
{
int one = (a[id(1, j)] + a[id(2, j)]) % 2;
cnt += (one != t);
t ^= 1;
}
printf("%d\n", min(ans, cnt));
}
else
{
int ans = 1e9;
memset(dp, 0x3f, sizeof dp);
rep(now, 0, 1 << 3) dp[1][now] = cal(now, 1);
_for(j, 2, m)
rep(pre, 0, 1 << 3)
rep(now, 0, 1 << 3)
if(check(pre, now))
{
dp[j][now] = min(dp[j][now], dp[j - 1][pre] + cal(now, j));
if(j == m) ans = min(ans, dp[j][now]);
}
printf("%d\n", ans);
}
return 0;
}