题目链接
A 寒假集训(差分、结构体排序)
思路
- 题目总共给了 n+m 个人,n 个已经进入工作室,m 个人是未进入的,
- 之后又 k 场比赛,每场比赛都会对一些区间的内的人进行加分,由于区间数量比较多肯定不可以暴力,所以要用差分维护区加法,
- k 场比赛之后,让我输出前 n 名的排名 id,这明显是结构体 sort 排序一下就行了,
- 具体看代码,,,,
#include<bits/stdc++.h>
using namespace std;
const int mxn = 200005;
struct Node
{
long long id, score;
} ar[mxn];
bool cmp(Node a, Node b)
{
if(a.score == b.score)
return a.id < b.id;
return a.score > b.score;
}
int main()
{
int T; scanf("%d", &T);
while(T --)
{
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
int t = n + m; //总人数
for (int i = 1; i <= t; i ++) //初始化
{
ar[i].id = i;
ar[i].score = 0;
}
while(k --)
{
int p, s; scanf("%d %d", &p, &s);
while(p --)
{
int l, r;
scanf("%d %d", &l, &r);
ar[l].score += s; //进行差分
ar[r + 1].score -= s;
}
}
for (int i = 1; i <= t; i ++) //求前缀和的得到每一个位置的加分过后之后的值
{
ar[i].score += ar[i - 1].score;
}
sort(ar + 1, ar + 1 + t, cmp);
int num = 0;
for (int i = 1; i <= n; i ++) //在前 n 名内找一下符合题意的数量
{
if(ar[i].id > n)
num ++;
printf("%lld\n", ar[i].id);
}
printf("%d\n\n", num);
}
return 0;
}
B最近比赛太难了 来道水题
思路
- 题目让求两场比赛的总分第 100 名的分数最少为多少?
- 这题越想越绕,其实就两句话,
- 第一句:两场比赛的 第 100 名的最低分至少是(a+b),
- 第二句:两场比赛的 第 100 名的最低分至少是 (c+d),
- 明显只能选择的 (a+b) 与(c+d) 大的那个数,因为大的那个数限制小的那个数的取值范围,
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long a, b, c, d;
scanf("%lld %lld %lld %lld", &a, &b, &c, &d);
long long ans = max(a + b, c + d);
printf("%lld\n", ans);
return 0;
}
最近比赛太水了 来道难题
思路
- 暴力做就行了
代码
#include<bits/stdc++.h>
using namespace std;
const int mxn = 1e5 + 10;
int ar[mxn];
int main()
{
int n; scanf("%d", &n);
for (int i = 1; i <= n; i ++)
{
scanf("%d", &ar[i]);
}
sort(ar + 1, ar + 1 + n);
for (int i = 100; ; i --)
{
int t = sqrt(ar[i]);
if(t * t != ar[i])
{
printf("%d\n", ar[i]);
break;
}
}
return 0;
}
这仗还打不打!!!!(贪心)
思路
- 这题是个贪心题,
- 首先 cxs 给每个学生讲任务的总时间是恒定的,
- 只不过给学生讲任务的顺序,造成学生做任务的起始时间不同,
- 要想让总时间尽肯能的少,就要的先给那些做任务耗时长的学生讲,那么他们就可以利用到更多的使用到 cxs 给其他学生讲任务的间隔,他们的任务就更可能在 cxs 给所有的学生讲完任务之前把任务完成,这样就可能使耗时更少
代码
#include<bits/stdc++.h>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
using namespace std;
const int mxn = 1e5 + 10;
struct Node
{
int a, b;
} ar[mxn];
bool cmp(Node x, Node y)
{
return x.b > y.b;
}
int main()
{
Run();
int n, cas = 1;
while(scanf("%d", &n) && n)
{
for (int i = 1; i <= n; i ++)
{
scanf("%d %d", &ar[i].a, &ar[i].b);
}
sort(ar + 1, ar + 1 + n, cmp);
int t = 0, now = 0;
for (int i = 1; i <= n; i ++)
{
now += ar[i].a;
t = max(t, now + ar[i].b);
}
printf("Case %d: %d\n", cas ++, t);
}
return 0;
}
It is water
- 规律题,分情况讨论一下就行了
思路
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long T; scanf("%lld", &T);
while(T --)
{
long long n, m;
scanf("%lld %lld", &n, &m);
long long ans;
if(n == 1)
{
ans = 0;
}
else if(n == 2)
{
ans = m;
}
else
{
ans = 2 * m;
}
printf("%lld\n", ans);
}
return 0;
}
这题不会有坑吧(简单贪心)
思路
- 第一种菜只能用碗,而第二种菜既可以用碗又可以用盘子,
- 哪我们的贪心思路就是,遇见第一中的菜的时候只能使用碗(碗的数量 - 1),如果碗不够就要的洗一个碗了(清洗数量 + 1),
- 如果遇见第二种菜,我们尽量先用盘子,盘子用完了在用碗,碗用完了 那就没办法了,只能 清洗次数 + 1
代码
#include<bits/stdc++.h>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
using namespace std;
const int mxn = 1e5 + 10;
int main()
{
Run();
int n, a, b, t, ans = 0;
scanf("%d %d %d", &n, &a, &b);
for (int i = 1; i <= n; i ++)
{
scanf("%d", &t);
if(t == 1)
{
if(a > 0)
{
a --;
}
else
{
ans ++;
}
}
else
{
if(b > 0)
{
b --;
}
else if(a > 0)
{
a --;
}
else
{
ans ++;
}
}
}
printf("%d\n", ans);
return 0;
}
听听,这说的是人话嘛?
思路
- 题目问我们能否在给的数字串中选择两个相同的子串,
- 其实我们只要能选两个长度为 1 的相同子串就行了,
- 其实转化一下就是求是否存在某个数字出现两个,
- 由于数据范围比较小,直接暴力判断就行了
代码
#include<bits/stdc++.h>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
using namespace std;
const int mxn = 1e5 + 10;
int ar[mxn];
int main()
{
int t; scanf("%d", &t);
while(t --)
{
int n, flag = 0; scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%d", &ar[i]);
for (int j = 1; j < i; j ++)
{
if(ar[i] == ar[j])
{
flag = 1;
break;
}
}
}
printf("%s\n", flag ? "Yes" : "No");
}
return 0;
}
带可莉出去玩~(后缀和+贪心)
思路
- 首先如果如果无法使用传送的话,那么只能从乖乖的从地点 1 走到 n,
- 因为有了传送,首先明确我们传送只能向着 n 所的在的那个方向传送,而且能穿多远就尽量传多远,传送的两个城市之间的路程耗时为 0,那么的选择传送地点的时候肯定是选的传送路程比较的大的那个城市进行传送,
- 至于怎么的找传送路程比较大的那个路程,用后缀和维护任意两个城市的直接的距离,枚举的枚举起点城市,维护一个距离最大值 mx 就行了,
- 答案就是总距离 sum-mx,
- 最后别忘了特殊讨论传送距离 k>=n 的情况,这个时候耗时为 0
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const int mxn = 1e6 + 10;
long long ar[mxn];
long long surfix[mxn];
int main()
{
long long n, k, sum = 0;
scanf("%lld %lld", &n, &k);
n --;
for (int i = 1; i <= n; i ++)
{
scanf("%lld", &ar[i]);
sum += ar[i];
}
if(k >= n) //进行一下特判,否则错
{
printf("0\n");
return 0;
}
for (int i = n; i >= 1; i --) //求前缀和
{
ar[i] += ar[i + 1];
}
ll mx = 0;
for (int i = n - k + 1; i >= 1; i --)
{
mx = max(mx, ar[i] - ar[i + k]);
}
printf("%lld\n", sum - mx);
return 0;
}
A + B and A - B
思路
直接看代码吧
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long long
#define ull unsigned long long
#define Pir pair<long long, long long>
#define m_p make_pair
#define for_(i, s, e) for(long long i = (long long)(s); i <= (long long)(e); i ++)
#define rep_(i, e, s) for(long long i = (long long)(e); i >= (long long)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define scanf scanf
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (long long)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const long long mxn = 2e5;
char f, a[mxn], b[mxn];
long long ar[mxn], br[mxn], cr[mxn];
void add(long long ar[], long long br[], long long la, long long lb)
{
long long ln = max(la, lb);
long long sur = 0;
for (int i = 0; i <= ln; i ++)
{
cr[i] = (ar[i] + br[i] + sur) % 10;
sur = (ar[i] + br[i] + sur) / 10;
}
long long x = ln;
while(x && cr[x] == 0) x --;
for (int i = x; i >= 0; i --) printf("%lld", cr[i]);
printf("\n");
}
bool cmp(long long ar[], long long br[], long long la, long long lb)
{
if(la > lb) return 1;
if(la < lb) return 0;
for (int i = la - 1; i >= 0; i --)
{
if(ar[i] < br[i]) return 0;
}
return 1;
}
void subtract(long long ar[], long long br[], long long la, long long lb)
{
long long ln = max(la, lb);
long long sub = 0;
for (int i = 0; i <= ln; i ++)
{
cr[i] = ar[i] - br[i] - sub;
if(cr[i] < 0)
sub = 1, cr[i] += 10;
else
sub = 0;
}
long long x = ln;
while(x && cr[x] == 0) x --;
for (int i = x; i >= 0; i --) printf("%lld", cr[i]);
printf("\n");
}
void init()
{
memset(ar, 0, sizeof ar);
memset(br, 0, sizeof br);
memset(cr, 0, sizeof cr);
}
int main()
{
long long T, cas = 1; scanf("%lld", &T);
while(T --)
{
getchar();
init();
scanf("%c %s %s", &f, a, b);
long long la = strlen(a);
long long lb = strlen(b);
reverse(a, a + la);
reverse(b, b + lb);
for (int i = 0; i < la; i ++) ar[i] = a[i] - '0';
for (int i = 0; i < lb; i ++) br[i] = b[i] - '0';
if(f == '+')
{
printf("Case %lld:加法\n", cas ++);
add(ar, br, la, lb);
}
else
{
printf("Case %lld:减法\n", cas ++);
if(cmp(ar, br, la, lb))
{
subtract(ar, br, la, lb);
}
else
{
printf("-");
subtract(br, ar, lb, la);
}
}
}
return 0;
}
简简单单
思路
- 水题直接看代码
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const int mxn = 1e6 + 10;
long long ar[mxn];
long long surfix[mxn];
long long C(ll m)
{
return m * (m - 1) / 2;
}
int main()
{
long long n, m;
scanf("%lld %lld", &n, &m);
ll sum = 0;
sum += C(n);
sum += C(m);
printf("%lld\n", sum);
return 0;
}
看看,这说的是人话嘛?(模拟)
思路
- 这题首先由 1~1e9 每个点代表一个盒子,之后给了我们 m 个不相交区间段的描述 l,r,v,表示 [l, r] 的所有点的权值为 v;没有区间描述过的点的权值默认为 0,当所有区间描述完之后,让我选择一个长度为 k 的子区间其区间权值和最大
- 这种题一看数据就知道没法暴力枚举区间 1~1e9 中所有长度为 k 的子区间段,
- 首先我先对区间按左端点进行进行 sort 排序,
- 之后我们可以从前向后循环先枚举所有的区间左端点 s,以 s 为开始长度为 k 的区间区间段,每次枚举都会产生一个最优值,
- 之后再从后向前循环枚举所有区间的右端点假设为 e,以 e 为结尾的长度为 k 的子区间,每次继续枚举都会产生一个最优值,
- 把所有答案的最优值维护一下 最优 就是答案了
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const ll mxn = 2e6 + 10;
struct Seg
{
ll l, r, c;
} seg[mxn];
bool cmp(Seg a, Seg b)
{
return a.l < b.l;
}
int main()
{
Run();
ll T; scanf("%lld", &T);
while(T --)
{
ll n, k;
scanf("%lld %lld", &n, &k);
for (int i = 1; i <= n; i ++)
{
scanf("%lld %lld %lld", &seg[i].l, &seg[i].r, &seg[i].c);
}
sort(seg + 1, seg + 1 + n, cmp);
seg[0] = (Seg){ 0, 0, 0 };
seg[n + 1] = (Seg){ INF, INF, 0 };
ll cost = 0, start, end; //now 现在的所选择的长度为 k 的区间的开始位置,end 为现在所选择长度为 k 的区间的结束位置, p 上一次所选择的区间的结束位置
ll sid = 0, eid = 1, ans = -INF; //sid 正在枚举区间的左端点所在的区间段下标位置;eid 为正在枚举区间的右端点的所在的区间段的下标
//正着枚举一遍维护最优值
for (int i = 1; i <= n; i ++)
{
start = seg[i].l;
end = start + k - 1;
cost -= seg[sid].c * (seg[sid].r - seg[sid].l + 1);
sid ++;
while(seg[eid].r <= end)
{
cost += seg[eid].c * (seg[eid].r - seg[eid].l + 1);
eid ++;
}
if(seg[eid].l <= end)
{
cost += seg[eid].c * (end - seg[eid].l + 1);
}
ans = max(ans, cost);
if(seg[eid].l <= end)
{
cost -= seg[eid].c * (end - seg[eid].l + 1);
}
}
seg[0] = (Seg){ -INF, -INF, 0 };
seg[n + 1] = (Seg){ 0, 0, 0 };
cost = 0, sid = n + 1, eid = n;
//倒着枚举一遍维护最优值
for (int i = n; i >= 1; i --)
{
start = seg[i].r;
end = start - k + 1;
cost -= seg[sid].c * (seg[sid].r - seg[sid].l + 1);
sid --;
while(seg[eid].l >= end)
{
cost += seg[eid].c * (seg[eid].r - seg[eid].l + 1);
eid --;
}
if(seg[eid].r >= end)
{
cost += seg[eid].c * (seg[eid].r - end + 1);
}
ans = max(ans, cost);
if(seg[eid].r >= end)
{
cost -= seg[eid].c * (seg[eid].r - end + 1);
}
}
printf("%lld\n", ans);
}
return 0;
}
听取 Wa 声一片
思路
- 这一题先用桶排的思想,统计一下每个数字出现的次数,
- 之后从小到大循环输出一个下,每个数 > 0 的数字,并且把这数字的数量 - 1,
- 如果还有的数字的次数 > 0 那么继续循环执行 2. 过程…
- 其实标程不是这样的,因为有一些同学没有学队列 queue 原因,所以数据没有有加强,因此没把上面👆说的那种暴力思路给卡掉,
- 正确的过程,首先我们的正常分析上面的那种思路话,每个数的取值范围是 0~1e6, 而且总的数字个数为 n<=1e6, 极端情况的话,当给的数据是 1e6 个 1e6 的话,由于 n 是 1e6 所以外出循环要执行 1e6 次,对于每次外层循环都要从 0~1e6 遍历一遍,所有极端情况总共会运行 1e12 次,超出了 1 秒最多可已运行大概 1e8 次的,所以会超时,
- 耗时的主要出现在的了 循环输出的那一部分,因此我们可以用队列把每个存在的数都压入队列,循环输出,当某数的次数为 0 的时候就不把它在压入队列了,这个样对于 n 为 1e6 的时候,只需要执行 1e6 次就可把所有的数输出出来了
暴力代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1e6+5;
typedef long long ll;
ll a[N],ak[N];
int main()
{
ll n,sum=0,maxa=-1e9;;
scanf("%lld",&n);
for(ll i=0; i<n; i++)
{
scanf("%lld",&a[i]);
if(maxa<a[i])
maxa=a[i];
ak[a[i]]++;
sum++;
}
//printf("%lld\n",sum);
while(sum)
{
for(ll i=0; i<=maxa; i++)
{
if(ak[i]>0)
{
printf("%lld ",i);
ak[i]--;
sum--;
}
}
}
return 0;
}
标准代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
long long n, m, t;
long long fac[1000005];
queue<long long >p;
long long mp[1000005];
long long ar[1000005];
int main()
{
long long i,j;
scanf("%lld",&n);
long long x;
for(i=0;i<n;i++)
{
scanf("%lld",&ar[i]);
mp[ar[i]]++;
}
sort(ar,ar+n);
n=unique(ar,ar+n)-ar;
for(i=0;i<n;i++)
{
p.push(ar[i]);
}
long long q=0;
while(!p.empty())
{
x=p.front();
p.pop();
mp[x]--;
if(q==0)
{
q=1;
printf("%lld",x);
}
else
{
printf(" %lld",x);
}
if(mp[x]>=1)
{
p.push(x);
}
}
return 0;
}