目录

写在前面

开始板刷1500了,主要是最近卡1300-1400上不去,发现cf很多思维题要不是想不到,要不就是签的慢,被读题卡了心态就巨难受,一下就不想写了,而且现在学知识点容易陷入递归,学到一个知识点发现需要用其他知识点,然后又去学其他知识点,然后学完还需要对这些一堆知识点做题练习不然只会板子根本没有什么对算法深刻的理解。感觉不如这样去板刷,遇到不会的只学这个不去学太多,在题目中理解知识点应该比单纯泛泛去学可能效果会更好。也记录一下,自己1500刷多少,才能有提升。

1. A. Did We Get Everything Covered?(构造、思维)

题目链接


A. Did We Get Everything Covered?


题意


给\(n,k\)以及长度为\(m\)的一个小写的字符串。

字符串的子序列是否包含用前\(k\)个小写字母构成的长度为n的字符串的所有情况


题解

  1. 首先判断有没有解:

    要构成所有的字符串,我们可以把原串进行拆分,拆分成n个段,每段如果都包含前k个小写字母至少一次,则说明有解,反之说明无解。
  2. 无解的情况下,考虑如何构造答案。

    用每一段最后一次出现的字符,加上不满足的段中没有出现的字符

    正确性?每一段最后出现的字符一定在前面没出现过,只能在后面出现,这样构造出来的子序列是正确的

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std;
const int mod=998244353;
void solve() {
int n,k,m;
string s;
cin>>n>>k>>m;
cin>>s;
set<char>cnt;
int cur=0;
string ans;
rep(i,0,m-1) {
cnt.insert(s[i]);
if(cnt.size()==k) {
ans+=s[i];
++cur;
cnt.clear();
}
if(cur>=n) {
cout<<"YES"<<endl;
return;
}
}
cout<<"NO"<<endl;
int len=ans.size();
rep(i,0,k-1) {
char c='a'+i;
if(cnt.count(c)==0) {
rep(j,1,n-len) ans+=c;
break;
}
}
cout<<ans<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

有判定正确性的思路,但是不会构造

wa了几发。最开始是构造的思路是错的

后面有一个小细节处理的不好,当要修改\(string\)时,就不能用\(string\)的\(size\)作为循环的控制条件,这样很容易寄。

很好的一道构造题目


2 F. Greetings(离散化+树状数组)

题目链接

F. Greetings

题意

题解

由于两个人的速度是一样的,所以到达终点之前两个人是不会相遇的,考虑一下什么情况两个人会相遇,其中一个人到达终点时,另一个人,终点所在地的前面,并且它的终点在更右边。

将两个人的起点终点分别用\(S_a 、S_b、 E_a、 E_b\)表示,并假设\(a\)在前\(b\)在后(b在前是对称的),有下图

  1. \(a\)的终点\(<\) \(b\)的终点,这时两者同时出发,a到终点时,b已经经过的a的终点,两者不会相遇,对答案没有贡献

  2. \(a\)的终点\(>\) \(b\)的终点,这时b会先到终点,速度一样,a此时还没有到达\(E_b\),此时两者一定会在\(E_b\)相遇



    所以答案转化为对于当前区间计算有多少个区间被它所包含。

因为这道题目数据的实际大小是没有意义的,相对大小是有用的,并且值域比较大,我们考虑离散化,然后通过树状数组去查询。

具体的做法是,先按右端点从小打大排序,然后从前往后遍历区间,每次查询起点大于当前点起点的个数。就是这个区间对答案产生的贡献。

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std; void solve() {
int n;
cin>>n;
struct node{
int l,r;
bool operator<(const node &t)const{
return r<t.r;
}
};
vector<node>a(n);
vector<int>b(2*n);
int k=0;
rep(i,0,n-1){
cin>>a[i].l>>a[i].r;
b[k++]=a[i].l;
b[k++]=a[i].r;
}
sort(b.begin(),b.end());
rep(i,0,n-1){
a[i].l=lower_bound(b.begin(),b.end(),a[i].l)-b.begin()+1;
a[i].r=lower_bound(b.begin(),b.end(),a[i].r)-b.begin()+1;
}
sort(a.begin(),a.end());
// rep(i,0,n-1){
// cout<<a[i].l<<' '<<a[i].r<<endl;
// }
vector<int>c(2*n+1,0);
auto lowbit=[](int x){
return x&-x;
}; auto add=[&](int x,int k)->void{
for(int i=x;i<=2*n;i+=lowbit(i)){
c[i]+=k;
}
}; auto sum=[&](int x){
int res=0;
for(int i=x;i;i-=lowbit(i)){
res+=c[i];
}
return res;
};
int ans=0;
rep(i,0,n-1){
int r=a[i].r,l=a[i].l;
ans+=sum(r)-sum(l-1);
add(l,1);
}
cout<<ans<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

  1. 离散化的板子记得不是很熟,这种东西应该很熟并且默写的很快的
  2. 树状数组用的还是比较少有些细节记得不太清,就比如树状数组的下标是从几开始的?

    答案是1,这就导致离散化的时候也要从1开始。
  3. 看了一些题解,发现了这类问题被称为二维偏序问题

    \(a_i<a_j、b_i>b_j\)

3. B. Milena and Admirer(贪心、小结论、思维)

题目链接

B. Milena and Admirer

题意

给一个长度为\(n\)的序列,我们通过操作使这个序列变成非递减序列

操作:对\(a[i]\),我们将\(a[i]\)删除,将\(a[i]-x、x\)插入原位置,要求\(x<a[i]\)

求最小的操作次数

题解

考虑贪心

对于满足\(a[i]<=a[i+1]\)的\(i\)我们不去操作

对于不满足条件的\(i\),我们考虑将\(a[i]\)拆成k个满足条件并且尽可能大的数。(这里k最多为\(a[i]-1\)因为一个数最多全部拆成1)。

考虑如何拆才能使答案最优,我们希望当前拆完的数尽可能大,在满足拆完的所有数都小于\(a[i+1]\)的情况下。,因为我们当前拆完的数的最小值会影响前面的数的拆分,我们肯定是希望拆完之后最小值最大的,如何才能达到最小值最大呢?

考虑去平均拆。

对于\(a[i+1]>a[i]\)需要将拆\(cnt=a[i]/a[i+1]+(a[i]%a[i+1]!=0)\)成这么多个数,需要拆

\(cnt-1\)次,还需要去维护一个最小值\(a[i]/cnt\),从后往前扫一遍维护最小值,统计答案即可。

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std; void solve() {
int n;
cin>>n;
vector<int>a(n+1);
rep(i,1,n) {
cin>>a[i];
}
int cur=1e9;
int ans=0;
//倒着枚举一遍
fep(i,n,1) {
if(a[i]<cur){
cur=a[i];
}else if(a[i]%cur==0){
ans+=a[i]/cur-1;
}else{
int cnt=a[i]/cur+1;
ans+=(cnt-1);
cur=a[i]/cnt;
}
}
cout<<ans<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

这道题目主要是要想清楚对于一个数如何拆分才能对后面的影响最小。


4. C. Smilo and Monsters(贪心、典题、结论)

题目链接

题意

题解

代码

总结


5. D. In Love(贪心)

题目链接

D. In Love

题意

线段的集合,有两种操作

  1. 插入一个线段
  2. 删除一个线段

    每次操作后都要去查询是否存在两个线段不相交

题解

首先先看两个线段不相交需要满足什么条件



也就是较\(大l>小r\)即可满足不相交

我们进行推广

当集合中,最大的\(l>\)最小的\(r\)时就存在区间不相交

注意是严格大于。

这样我们只需要维护两个集合,左端点的集合和右端点的集合,然后每次查询集合中的最值。

\(set\)和\(multiset\)都可以完成这件事,这道题目里面区间可能重复,所以用\(multiset\)去维护最大值最小值即可。

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std; void solve() {
int q;
cin>>q; multiset<int>sl,sr;
while(q--){
char op;
cin>>op;
int l,r;
cin>>l>>r;
if(op=='+'){
sl.insert(l);
sr.insert(r);
}else{
sl.erase(sl.find(l));
sr.erase(sr.find(r));
}
if(sl.size()<=1||sr.size()<=1){
cout<<"NO"<<endl;
continue;
}
int d=(*sl.rbegin())-(*sr.begin());
if(d>0){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
// cin>>_;
// while(_--)
solve();
return 0;
}

总结

  1. 区间不相交的充要条件
  2. multiset的erase用法

    不小心就用错了,erase可以传入迭代器的位置,也可以传入要删除的值,如果在set里面这两个都可以,在multiset里面一个值可能出现多次,如果传入值,就会把这所有数都删除,如果只想删除一个,可以先用find函数得到一个迭代器的位置再删除

6. C. Card Game(思维、找性质)

题目链接

C. Card Game

题面

题解

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std; void solve() {
int n;
cin>>n;
vector<int>a(n+1);
rep(i,1,n){
cin>>a[i];
}
int ans=0;
if(n==1){
if(a[1]>0){
cout<<a[1]<<endl;
}else{
cout<<0<<endl;
}
return;
}else {
if(a[1]>0){
ans+=a[1];
if(a[2]>0){
ans+=a[2];
}
}else{
ans=max(0*1ll,a[1]+a[2]);
}
rep(i,3,n){
if(a[i]>0) ans+=a[i];
}
}
cout<<ans<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

7 E. Block Sequence

链接

E. Block Sequence

题意

一个数组删除最少的数使数组变为美丽的

美丽的定义:

第一个数是长度看,后面k是k个数。

题解

考虑dp

\(f[i]\)表示将从i到n的所有数都变成美丽的花费最小

转移

\(f[i]=min(f[i+1]+1,f[i+a[i]+1]);\)

初始化:

\(f[n]=1;\)

\(f[n+1]=0\):这里表示一个都不删从第一个到第n个恰好是美丽的

这个是从后往前推,所以是倒序循环。

答案就是\(f[1]\)

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back using namespace std; void solve() {
int n;
cin>>n;
vector<int>a(n+2);
rep(i,1,n){
cin>>a[i];
}
vector<int>f(n+2);
f[n]=1;
f[n+1]=0;
fep(i,n-1,1){
f[i]=f[i+1]+1;
if(i+a[i]<=n){
f[i]=min(f[i],f[i+a[i]+1]);
}
}
cout<<f[1]<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

非常不错的一道dp题目。

给自己的启发是dp的顺序不止能从前往后,也可以逆序,只要初始化好状态。


8 B. Effects of Anti Pimples(调和级数、埃式筛思想)

题目链接

B. Effects of Anti Pimples

题面

题解

对于每个数,如果它被选上,那么所有它的倍数都会被选上,我们关心的是这些数中的最大值,可以类似线性筛一样,把每个数都变成这个最大值,然后对于计算每个数对于答案的贡献,问题就转化成了,所有子序列的最大值的和。

这个问题我们可以通过排序+快速幂解决。

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define vi vector<int> using namespace std;
const int mod=998244353; int ksm(int a,int b,int p){
int res=1;
while(b){
if(b&1){
res=res*a%p;
}
a=a*a%p;
b>>=1;
}
return res;
} void solve() {
int n;
cin>>n;
vi a(n+1);
rep(i,1,n){
cin>>a[i];
}
rep(i,1,n){
for(int j=i+i;j<=n;j+=i){
a[i]=max(a[i],a[j]);
}
}
sort(a.begin()+1,a.end());
int ans=0;
rep(i,1,n){
ans=(ans+a[i]*ksm(2,i-1,mod)%mod)%mod;
}
cout<<ans<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
// cin>>_;
// while(_--)
solve();
return 0;
}

总结

  1. 快速幂这些东西经常用的不能写错
  2. 这种倍数,会很容易和筛法结合,很重要的思想。

9 G. ABBC or BACB(思维、找规律、找性质)

链接

G. ABBC or BACB

题面

题解

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define vi vector<int> using namespace std; void solve() {
string s;
cin>>s;
int num=0,sum=0;
vi a;
rep(i,0,s.size()-1){
if(s[i]=='A'){
num++;
}else{
a.pb(num);
num=0;
}
}
a.pb(num);
sum=accumulate(a.begin(),a.end(),0);
cout<<sum-*min_element(a.begin(),a.end())<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

  1. 性质很重要
  2. 多手模几个样例

    学到了两个stl中的算法
  3. accumulate(a.begin(),a.end(),0):时间复杂度是\(O(n)\)的
  4. min_element(a.begin(),a.end()):返回的是迭代器。

10 E. Data Structures Fan(异或性质、前缀和思想)

链接

E. Data Structures Fan

题面



题解

异或的性质。

当异或遇到区间。

考虑用前缀和的思想解决。

这里分开处理0和1,因为最后我们要查询的是所有1和0位置处的\(a[i]\)的异或

我们考虑修改一段区间对于0、1的影响,我们希望将一段区间内的0处变成1,1变成0

然后假设我们现在这一段区间是\([3,8]\)

0:a[3] ^ a[5] ^ a[6]

1:a[4] ^ a[7] ^ a[8]

要使两者交换就需要异或上a[3] ^ a[4] ^ a[5] ^ a[6] ^ a[7] ^ a[8],也就是这个区间内所有数的异或

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define vi vector<int> using namespace std; void solve() {
int n;
cin>>n;
vector<int>a(n+1);
vector<int>sum(n+1);
rep(i,1,n){
cin>>a[i];
sum[i]=sum[i-1]^a[i];
}
string s;
cin>>s;
vector<int>ans(2);
rep(i,0,s.size()-1){
if(s[i]=='0') ans[0]^=a[i+1];
else ans[1]^=a[i+1];
}
int q;
cin>>q;
while(q--){
int op;
cin>>op;
if(op==1){
int l,r;
cin>>l>>r;
ans[0]^=(sum[r]^sum[l-1]);
ans[1]^=(sum[r]^sum[l-1]);
}else{
int d;
cin>>d;
cout<<ans[d]<<' ';
}
}
cout<<endl;
} signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
cin>>_;
while(_--)
solve();
return 0;
}

总结

  1. 所有逆运算的都可以通过前缀和思想来进行处理

    • 加减
    • 乘除
    • 异或、异或

Codeforces(1500板刷)的更多相关文章

  1. (NOIP)CSP-S 2019前计划

    前言 无 1.NOIP原题板刷 NOIP原题板刷 这是一篇咕了的blog 2.牛客 & ACwing & 洛谷 网课学习 收获还是蛮大的,不过我没有写博客 3.codeforces专项 ...

  2. Codeforces 图论题板刷(2000~2400)

    前言 首先先刷完这些在说 题单 25C Roads in Berland 25D Roads not only in Berland 9E Interestring graph and Apples ...

  3. 【 CodeForces 604A】B - 特别水的题2-Uncowed Forces

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=102271#problem/B Description Kevin Sun has jus ...

  4. Codeforces Gym 100342J Problem J. Triatrip 求三元环的数量 bitset

    Problem J. Triatrip Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/at ...

  5. Codeforces Round #285 (Div. 2) A B C 模拟 stl 拓扑排序

    A. Contest time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  6. Codeforces Round #334 (Div. 2) A. Uncowed Forces 水题

    A. Uncowed Forces Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/604/pro ...

  7. Codeforces Gym 100342J Problem J. Triatrip bitset 求三元环的数量

    Problem J. TriatripTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/att ...

  8. Codeforces Round #218 (Div. 2)

    500pt, 题目链接:http://codeforces.com/problemset/problem/371/A 分析:k-periodic说明每一段长度为k,整个数组被分成这样长度为k的片段,要 ...

  9. Codeforces Round #425 (Div. 2)C

    题目连接:http://codeforces.com/contest/832/problem/C C. Strange Radiation time limit per test 3 seconds ...

  10. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3)(A.B.C,3道暴力题,C可二分求解)

    A. Is it rated? time limit per test:2 seconds memory limit per test:256 megabytes input:standard inp ...

随机推荐

  1. 第三届人工智能,大数据与算法国际学术会议 (CAIBDA 2023)

    第三届人工智能,大数据与算法国际学术会议 (CAIBDA 2023) ​ 大会官网:http://www.caibda.org/ 大会时间:2023年6月16-18日 大会地点:中国郑州 截稿日期:2 ...

  2. tensorflow语法【zip、tf.tile、tf.truncated_normal、tf.data.Dataset.from_tensor_slices、dataset中shuffle()】

    相关文章: [一]tensorflow安装.常用python镜像源.tensorflow 深度学习强化学习教学 [二]tensorflow调试报错.tensorflow 深度学习强化学习教学 [三]t ...

  3. 『深度学习项目四』基于ResNet101人脸特征点检测

    相关文章: [深度学习项目一]全连接神经网络实现mnist数字识别 [深度学习项目二]卷积神经网络LeNet实现minst数字识别 [深度学习项目三]ResNet50多分类任务[十二生肖分类] 『深度 ...

  4. 驱动开发:WinDBG 配置内核双机调试

    WinDBG 是在windows平台下,强大的用户态和内核态调试工具,相比较于Visual Studio它是一个轻量级的调试工具,所谓轻量级指的是它的安装文件大小较小,但是其调试功能却比VS更为强大, ...

  5. C/C++ 反汇编:数据类型与常量

    反汇编即把目标二进制机器码转为汇编代码的过程,该技术常用于软件破解.外挂技术.病毒分析.逆向工程.软件汉化等领域,学习和理解反汇编对软件调试.系统漏洞挖掘.内核原理及理解高级语言代码都有相当大的帮助, ...

  6. IIS的详细配置

    一:配置默认文档 输入ip打开哪个页面是由默认文档设定的 1.打开IIS配置页面,点击网站.我们的默认站点已经启动,可以看到绑定的ip和网页的路径 2.选中Default Web Site,可以看到有 ...

  7. 多个request接口的功能优化处理速度

    一.原始代码功能如下,包含两个request接口的调用,耗时情况约4秒 import datetime import time import requests start_time = datetim ...

  8. 【Unity3D】表面着色器

    1 前言 ​ 固定管线着色器一.固定管线着色器二 中介绍了 ShaderLib 的基本用法,本文将接着讲解表面着色器(Surface Shader)的用法.固定管线着色器基于 ShaderLib 命令 ...

  9. c# 代码操作ftp服务器文件

    好久不见,我又回来了.给大家分享一个最近c#代码操作ftp服务器的代码示例 1 public abstract class FtpOperation 2 { 3 /// <summary> ...

  10. nginx新增conf文件

    说明 最近租了一台美国vps,通过nginx反向代理设置搞谷歌镜像.因为BxxDx搜索太垃圾.中间涉及到添加反向代理配置. 操作步骤 1.在conf.d文件下新增配置 cd /etc/nginx/co ...