2024 国庆做题总结
Secret Santa
思路
这是一个需要深思熟虑的贪心,总之还算有点复杂。
首先,如果一个数不在它自己数值的下标上,就可以填进去,将剩下的还未填的数记录下来,此时情况如下(样例1,第一组):
当前:2 1 _
剩余:3
然后将剩余的数的那个数组反过来,即从大到小排序,填满空位,这样可能会有冲突,但是,可以证明只会有一个冲突。
证明:
那么如何解决掉冲突呢,将冲突位置上的值替换为之前这个位置上的值即可,再将之前这个位置上的值的现在的位置上的值改为冲突位置的值,这样就不会有冲突。
原来:2 1 3 位置 3 上有冲突
更改后:3 1 2 (第三个位置改为原来的值,第一个位置改为 3)
显然这种方案变换次数最少。
代码
#include<iostream>
#include<vector>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 2e5 + 10;
int T, n, ans;
int a[N], b[N], cnt[N], tot;
vector<int> v[N];
bool vis[N], f[N];
int main(){
T = read();
while (T--){
n = read();
for (int i = 1; i <= n; i++) a[i] = read(), v[a[i]].push_back(i);
for (int i = 1; i <= n; i++){
for (auto j : v[i]){
if (!vis[j] && i != j){
b[j] = i;
vis[j] = 1;
f[i] = 1;
break;
}
}
if (!f[i]) cnt[++tot] = i;
}
for (int i = 1, l = tot; i <= n && l >= 1; i++){
if (!vis[i]) b[i] = cnt[l], l--;
}
for (int i = 1; i <= n; i++){
if (b[i] == i) swap(b[i], b[v[a[i]][0]]);
}
for (int i = 1; i <= n; i++){
if (a[i] == b[i]) ans++;
}
cout << ans << '\n';
for (int i = 1; i <= n; i++) cout << b[i] << ' ';
cout << '\n';
for (int i = 1; i <= n; i++) a[i] = b[i] = cnt[i] = vis[i] = f[i] = 0;
for (int i = 1; i <= n; i++) v[i].clear();
tot = ans = 0;
}
return 0;
}
[ABC137D] Summer Vacation
思路
考虑从后往前做,只剩一天时,只能选取一天之后才能拿到工资的任务,显然选取能拿到工资最多的,那么假如还剩下
代码
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e5 + 10;
int n, m, ans;
struct node{
int a, b;
bool operator < (const node &b) const{
return a < b.a;
}
}x[N];
priority_queue<int> q;
int main(){
n = read(), m = read();
for (int i = 1; i <= n; i++) x[i].a = read(), x[i].b = read();
sort(x + 1, x + n + 1);
int top = 1;
for (int i = 1; i <= m; i++){
while (x[top].a <= i && top <= n){
q.push(x[top++].b);
}
if (!q.empty()) ans += q.top(), q.pop();
}
cout << ans;
return 0;
}
P4377 [USACO18OPEN] Talent Show G
思路
错解:01背包,当前总才艺值时,最小的重量值,求答案。
为什么错误?因为总重量值有一个限制,要大于等于
正解:考虑二分答案,现在二分到了一个答案
由此可知,选取一定的
代码
#include<iostream>
#include<climits>
#define INF INT_MIN
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 255, M = 1e3 + 10;
const double eps = 10e-10;
int n, W;
double ans;
int w[N], t[N], sum;
double p[N], dp[M];
bool check(double x){
for (int i = 1; i <= W; i++) dp[i] = -INF;
for (int i = 1; i <= n; i++) p[i] = (double)t[i] - x * w[i];
for (int i = 1; i <= n; i++)
for (int j = W + w[i]; j >= w[i]; j--)
dp[min(j, W)] = max(dp[min(j, W)], dp[j - w[i]] + p[i]);
return dp[W] >= 0;
}
signed main(){
n = read(), W = read();
for (int i = 1; i <= n; i++) w[i] = read(), t[i] = read(), sum += w[i];
double l = 0, r = 1000000;
while (l + eps <= r){
double mid = (l + r) / 2;
if (check(mid)){
l = mid;
}else{
r = mid;
}
}
cout << (int)(l * 1000);
return 0;
}
[ARC110D] Binomial Coefficient is Fun
思路
题目
代码
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 2e3 + 10, mod = 1e9 + 7;
int n, m, sum;
int a[N];
int qpow(int a, int b){
int ans = 1;
while (b){
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int C(int m, int n){
int ans = 1;
for (int i = n; i >= n - m + 1; i--) ans = ans * i % mod;
for (int i = 1; i <= m; i++) ans = ans * qpow(i, mod - 2) % mod;
return ans;
}
signed main(){
n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read(), sum += a[i];
cout << C(sum + n, m + n);
return 0;
}
[AGC001E] BBQ Hard
思路
是个很妙的题目,直接暴力求必须要
首先有一个结论,
所以设
但是,统计答案还是需要
初始时将每个
代码
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 2e5 + 10, M = 4e3 + 20, mod = 1e9 + 7;
int n, sum;
int a[N], b[N], dp[M + 10][M + 10], v[M << 1 + 10], inv[M << 1 + 10];
int qpow(int a, int b){
int ans = 1;
while (b){
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init(){
v[0] = inv[0] = 1;
for (int i = 1; i <= (M << 1); i++){
v[i] = v[i - 1] * i % mod;
inv[i] = qpow(v[i], mod - 2);
}
}
int C(int m, int n){
return v[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main(){
init();
n = read();
for (int i = 1; i <= n; i++) a[i] = read(), b[i] = read(), dp[M / 2 - a[i]][M / 2 - b[i]]++;
for (int i = 1; i <= M; i++)
for (int j = 1; j <= M; j++) dp[i][j] = (dp[i][j] + (dp[i - 1][j] + dp[i][j - 1]) % mod) % mod;
for (int i = 1; i <= n; i++) sum = (sum + dp[M / 2 + a[i]][M / 2 + b[i]]) % mod;
for (int i = 1; i <= n; i++) sum = (sum - C(2 * a[i], 2 * a[i] + 2 * b[i]) + mod) % mod;
cout << sum * qpow(2, mod - 2) % mod;
return 0;
}
P7044 「MCOI-03」括号
思路
对于一个位置为
代码
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e6 + 10, M = 4e6 + 10, mod = 998244353;
int n, k, ans;
char c[N];
int x[N], mul[M], inv[M];
int stk[N], top;
int qpow(int a, int b){
int ans = 1;
while (b){
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init(){
mul[0] = inv[0] = 1;
for (int i = 1; i <= M - 10; i++) mul[i] = mul[i - 1] * i % mod, inv[i] = qpow(mul[i], mod - 2);
}
int C(int m, int n){
if (n < 0 || m > n) return 0;
return mul[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main(){
init();
n = read(), k = read();
cin >> c + 1;
for (int i = 1; i <= n; i++){
if (c[i] == '(') stk[++top] = i;
else{
if (!top) x[i] = 0;
else x[i] = stk[top], x[stk[top--]] = i;
}
}
while (top) x[stk[top--]] = n + 1;
for (int i = 1; i <= n; i++){
if (c[i] == '(') ans = (ans + C(i - 1, k + i - 1) * ((C(n - i, k + n - i) - C(n - x[i], k + n - x[i]) + mod) % mod) % mod) % mod;
else ans = (ans + C(n - i, k + n - i) * ((C(i - 1, k + i - 1) - C(x[i] - 1, k + x[i] - 1) + mod) % mod) % mod) % mod;
}
cout << ans;
return 0;
}
Anton and School - 2
思路
对于一个空处,左边有
于是,预处理一个空位左边左括号个数和右括号个数,再用公式统计即可。
代码
#include<iostream>
#include<cstring>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 2e5 + 10, M = 4e5 + 10, mod = 1e9 + 7;
int n, ans;
char c[N];
int pre[N], suf[N], mul[M << 1], inv[M << 1];
int qpow(int a, int b){
int ans = 1;
while (b){
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init(){
mul[0] = inv[0] = 1;
for (int i = 1; i <= (n << 1); i++) mul[i] = mul[i - 1] * i % mod, inv[i] = qpow(mul[i], mod - 2);
}
int C(int m, int n){
return mul[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main(){
cin >> c + 1;
n = strlen(c + 1);
init();
for (int i = 1; i <= n; i++){
pre[i] = pre[i - 1];
if (c[i] == '(') pre[i] = pre[i - 1] + 1;
}
for (int i = n; i >= 1; i--){
suf[i] = suf[i + 1];
if (c[i] == ')') suf[i] = suf[i + 1] + 1;
}
for (int i = 1; i <= n; i++){
if (c[i] == '('){
ans = (ans + C(pre[i], pre[i] + suf[i] - 1)) % mod;
}
}
cout << ans;
return 0;
}
P9118 [春季测试 2023] 幂次
思路
当
当
当
代码
#include<iostream>
#include<cmath>
#include<map>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
int n, k, ans;
map<int, bool> vis;
signed main(){
n = read(), k = read();
if (k == 1){
cout << n;
}else if (k == 2){
ans += sqrtl(n);
for (int p = 2; p * p * p <= n; p++){
for (int i = 2, sum = p * p; ; i++){
if (i >= k && i % 2 != 0 && !vis[sum]) vis[sum] = 1, ans++;
if (i % 2 == 0) vis[sum] = 1;
if (sum <= n / p) sum *= p;
else break;
}
}
cout << ans;
}else{
for (int p = 2; p * p * p <= n; p++){
for (int i = 2, sum = p * p; ; i++){
if (i >= k && !vis[sum]) vis[sum] = 1, ans++;
if (sum <= n / p) sum *= p;
else break;
}
}
cout << ans + 1;
}
return 0;
}
P9869 [NOIP2023] 三值逻辑
思路
令
代码
#include<iostream>
#include<vector>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e5 + 10;
int id, T, n, m, ans;
int a[N];
bool b[N], vis[N], l[N];
vector<int> e[N];
void get_ans(int u){
if (vis[u]) return;
ans++;
vis[u] = 1;
for (auto v : e[u]) get_ans(v);
}
void modify(int u){
if (vis[u]) return;
vis[u] = 1;
for (auto v : e[u]) modify(v);
}
int main(){
id = read(), T = read();
while (T--){
n = read(), m = read();
for (int i = 1; i <= n + 3; i++) a[i] = i, b[i] = 0, vis[i] = 0, l[i] = 0;
for (int i = 1; i <= n + 3; i++) e[i].clear();
ans = 0;
for (int i = 1; i <= m; i++){
char c; cin >> c;
if (c == '+'){
int x = read(), y = read();
a[x] = a[y];
b[x] = b[y];
}else if (c == '-'){
int x = read(), y = read();
a[x] = a[y];
b[x] = b[y] ^ 1;
}else if (c == 'T'){
int x = read();
a[x] = a[n + 1];
b[x] = b[n + 1];
}else if (c == 'F'){
int x = read();
a[x] = a[n + 2];
b[x] = b[n + 2];
}else{
int x = read();
a[x] = a[n + 3];
b[x] = b[n + 3];
}
}
for (int i = 1; i <= n; i++) e[a[i]].emplace_back(i);
for (int i = 1; i <= n; i++) if (a[i] == i && b[i]) get_ans(i);
get_ans(n + 3);
ans--;
for (int i = 1; i <= n; i++){
if (vis[i]) continue;
int u = a[i];
l[i] = 1;
while (!l[u]){
l[u] = 1;
u = a[u];
}
int p = a[u], sum = b[u];
while (p != u){
sum += b[p];
p = a[p];
}
if (sum & 1) get_ans(u);
else modify(u);
}
cout << ans << '\n';
}
return 0;
}
本文作者:bryce_yyds
本文链接:https://www.cnblogs.com/bryceyyds/p/18438463
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话