A
二分 + 容斥
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
LL Gcd(LL a, LL b){
return b == 0 ? a : Gcd(b, a % b);
}
LL Lcm(LL a, LL b){
return a / Gcd(a, b) * b;
}
LL Check(LL a, LL b, LL c, LL n){
LL ans;
ans = n / a + n / b + n / c;
ans = ans - n / (Lcm(a, b)) - n / (Lcm(a, c)) - n / (Lcm(b, c));
ans = ans + n / (Lcm(a, Lcm(b, c)));
return ans;
}
int main(){
LL a, b, c, n;
while(scanf("%lld%lld%lld%lld", &a, &b, &c, &n) != EOF){
LL ans;
LL minx = min(a, min(b, c));
if(n < minx){
printf("%lld\n", n);
continue;
}
LL l = n, r = 1e18;
while(l <= r){
LL mid = (l + r) / 2;
LL tmp = Check(a, b, c, mid);
if(mid - tmp >= n){
ans = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
printf("%lld\n", ans);
}
return 0;
}
注意只有y坐标是可以以倍数形式去走得,这里可以考虑素数的线性晒法,然后更新答案的时候有个记录就行
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const LL INF = 1e17;
LL dp[21][10005];
LL maxn[21][10005];
int main(){
int t; scanf("%d", &t);
while(t--){
int n, m; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
scanf("%lld", &dp[i][j]);
maxn[i][j] = -INF;
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
if(i == 1 && j == 1){
for(int k = j + j; k <= m; k += j)
maxn[i][k] = max(maxn[i][k], dp[i][j]);
continue;
}
LL t = maxn[i][j];
if(i - 1 >= 1) t = max(t, dp[i - 1][j]);
if(j - 1 >= 1) t = max(t, dp[i][j - 1]);
dp[i][j] += t;
for(int k = j + j; k <= m; k += j)
maxn[i][k] = max(maxn[i][k], dp[i][j]);
}
printf("%lld\n", dp[n][m]);
}
return 0;
}
C
实际上是个组合数学题,首先每天给k个题,还剩下n = n - m * k, 实际上要讨论的问题就是把n分解成m个部分,你可以把这n看成n个1,然后分成m个部分,但是有些部分可以为0,所以实际求得组合数是C(n + m - 1, m - 1),然后就是关于如何计算末尾有多少个0, 可以参考:传送门 , 然后把组合数全部化成阶乘的形式就可以算结果了
推荐一道类似的题:传送门
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
LL Cal(LL n, LL k){
LL cnt = 0;
while(n > 0){
cnt += n / k;
n /= k;
}
return cnt;
}
int main(){
LL n, m, k;
while(scanf("%lld%lld%lld", &m, &n, &k) != EOF){
n = n - m * k;
if(n <= 0){
puts("0");
continue;
}
LL a = Cal(n + m - 1, 5) - Cal(n, 5) - Cal(m - 1, 5);
LL b = Cal(n + m - 1, 2) - Cal(n, 2) - Cal(m - 1, 2);
printf("%lld\n", min(a, b));
}
return 0;
}
D
推出公式之后就是个矩阵快速幂了、
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e8;
struct Rec{
LL mar[3][3];
Rec(){
mst(mar, 0);
}
Rec operator * (const Rec &d)const{
Rec tmp;
mst(tmp.mar, 0);
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
for(int k = 0; k < 2; ++k){
tmp.mar[i][j] = (tmp.mar[i][j] + (mar[i][k] * d.mar[k][j] % MOD + MOD) % MOD + MOD) % MOD;
}
return tmp;
}
}ans, f;
void Quick(LL n, LL f1){
mst(ans.mar, 0);
ans.mar[0][0] = 3, ans.mar[0][1] = 1;
ans.mar[1][1] = 1;
mst(f.mar, 0);
f.mar[0][0] = f.mar[1][1] = 1;
while(n > 0){
if(n & 1) f = f * ans;
n >>= 1;
ans = ans * ans;
}
}
int main(){
LL a, b, n;
while(scanf("%lld%lld%lld", &a, &b, &n) != EOF){
a %= MOD;
b %= MOD;
LL f1 = (a + b) % MOD;
Quick(n, f1);
LL res = (f1 * f.mar[0][1] + f1) % MOD;
printf("%lld\n", (res + MOD) % MOD);
}
return 0;
}
E
先把宝藏数量分成尽可能平均的两部分,然后求出这两部分分出的所有结果的差,然后枚举其中一个去二分找另外一个的最好匹配(也就是差值最小),有些小技巧
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 40;
double x[qq], y[qq];
double ans[1 << 19], cns[1 << 19];
int t1, t2;
void Solve(double *p, int n, int f){
LL minx = 1e15;
for(int i = 0; i < (1 << n); ++i){
double sum1, sum2, sum;
sum1 = sum2 = sum = 0.0;
for(int j = 0; j < n; ++j){
sum += p[j];
if(i & (1 << j)) sum1 += p[j];
}
sum2 = sum - sum1;
minx = abs(sum1 - sum2);
if(f == 1){
ans[t1++] = max(sum2, sum1) - min(sum2, sum1);
}else{
cns[t2++] = min(sum2, sum1) - max(sum2, sum1);
}
}
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
int q1, q2;
q1 = q2 = 0;
t1 = t2 = 0;
for(int i = 1; i <= n / 2; ++i)
scanf("%lf", &x[q1++]);
for(int i = n / 2 + 1; i <= n; ++i)
scanf("%lf", &y[q2++]);
if(n == 1){
printf("%.2lf\n", y[0]);
continue;
}
Solve(x, q1, 1);
Solve(y, q2, 2);
for(int i = 0; i < t2; ++i)
cns[i] = -cns[i];
sort(cns, cns + t2);
cns[t2] = 1e15;
double minx = 1e15;
for(int i = 0; i < t1; ++i){
int k = lower_bound(cns, cns + t2, ans[i]) - cns;
double t = abs(ans[i] - cns[k]);
if(k + 1 < t1) t = min(t, abs(ans[i] - cns[k + 1]));
if(k - 1 >= 0) t = min(t, abs(ans[i] - cns[k - 1]));
minx = min(minx, t);
}
printf("%.2lf\n", minx);
}
return 0;
}
F
NIM游戏的裸题、
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
LL num[qq];
int main(){
int n;
while(scanf("%d", &n) != EOF){
LL ans = 0;
for(int i = 0; i < n; ++i){
scanf("%lld", num + i);
ans ^= num[i];
}
if(ans == 0){
printf("0\n");
continue;
}
int maxn = 0, cnt = 0;
LL p = ans;
while(p > 0){
if(p & 1) maxn = cnt;
cnt++;
p >>= 1;
}
int res = 0;
for(int j = 0; j < n; ++j){
if(num[j] & (1 << maxn)) res++;
}
printf("%d\n", res);
}
return 0;
}
参考:传送门
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
LL Quick(LL a, LL b){
if(b <= 0) return 1;
LL ans = 1;
while(b){
if(b & 1) ans = (ans * a) % MOD;
a = (a * a) % MOD;
b >>= 1;
}
return ans;
}
int main(){
int t; scanf("%d", &t);
while(t--){
int n; scanf("%d", &n);
if(n < 3){
printf("%d\n", n);
continue;
}
LL ans;
if(n % 3 == 1) ans = (Quick(3, n / 3 - 1) * 4) % MOD;
else if(n % 3 == 2) ans = (Quick(3, n / 3) * 2LL) % MOD;
else ans = Quick(3, n / 3);
printf("%lld\n", ans);
}
return 0;
}
J
比赛的节奏没掌握好,这题也是道简单题,用两个树状数组维护一下收入和人数,因为收入有0的情况,不妨把整体向右平移一位
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 2e6 + 10;
LL mon[qq], peo[qq];
int lowbit(int x){
return x & (-x);
}
void Update(LL *p, int x, int v){
while(x < qq){
p[x] += v;
x += lowbit(x);
}
}
LL Getsum(LL *p, int x){
LL ans = 0;
while(x > 0){
ans += p[x];
x -= lowbit(x);
}
return ans;
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
mst(mon, 0), mst(peo, 0);
int a, b, op;
while(n--){
scanf("%d", &op);
if(op == 0){
scanf("%d", &a);
a++;
Update(mon, a, a);
Update(peo, a, 1);
}else{
scanf("%d%d", &a, &b);
a++, b++;
int k = Getsum(peo, b) - Getsum(peo, a - 1);
if(k == 0){
puts("zhizhiwuwu");
continue;
}
LL money = Getsum(mon, b) - Getsum(mon, a - 1);
printf("%lld\n", (money - k) / k);
}
}
puts("");
}
return 0;
}
其实和普通的除法一样,小学奥数的举一反三?
a/b 的第n位是多少取决于n-1位模b的结果,然后递归即可,这里数据较大,采用快速幂直接计算
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e3 + 5;
vector<int> vt[qq];
int num[10005];
LL Quick(LL a, LL b, LL MOD){
LL ans = 1;
while(b){
if(b & 1) ans = (ans * a) % MOD;
a = (a * a) % MOD;
b >>= 1;
}
return ans;
}
int main(){
LL a, b, n;
while(scanf("%lld%lld%lld", &a, &b, &n) != EOF){
printf("%lld\n", ((a % b) * Quick(10LL, n - 1, b) % b) * 10 / b);
}
return 0;
}
M
dp[i][j] 代表n个节点有m个叶子节点的情况数量.
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define REP(i, x, n) for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
LL dp[55][55];
LL Dfs(int n, int m){
if(dp[n][m] != -1) return dp[n][m];
dp[n][m] = 0;
for(int i = 0; i <= n - 1; ++i)
for(int j = 0; j <= i && j <= m; ++j){
(dp[n][m] += (Dfs(i, j) * Dfs(n - i - 1, m - j)) % MOD) %= MOD;
}
return dp[n][m];
}
int main(){
LL n, m;
mst(dp, -1);
dp[0][0] = 1;
dp[1][0] = 0;
dp[1][1] = 1;
while(scanf("%d%d", &n, &m) != EOF){
if(dp[n][m] == -1) Dfs(n, m);
printf("%lld\n", dp[n][m]);
}
return 0;
}