这场可能是因为stl和kmp用的熟,并且前段时间遇到过一道跟取余有关系的题给了思路比较接近,所以abcd都秒了。e题有思路,但是写不出来,f回头想了下觉得挺简单的。四题过后对应rank可以到前30。
总结:
- 犯了一个错误1e9的长度当成了9
- nex数组初始值nex0=-1,这个不太熟练,浪费了几分钟
- e题没有沉下头写
- f题没有多想
题解
A
题意:给你一个字符串s,求怎样构造出一个字付串t,使他的子串包含k个s。求最短的t(s长度和k<50)
思路:考虑前缀和后缀最长相同长度。可以暴力,也可以kmp nex数组。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 1e4+5;
int nex[maxn];
void getnex(string s){
int n = s.size(),i = 0,j = -1;
nex[0] = -1;
while(i<n){
if(s[i]==s[j]||j==-1) nex[++i] = ++j;
else j = nex[j];
//cerr<<i<<' '<<j<<'
';
}
}
int main(){
IO;
int n,k;cin>>n>>k;
string s;cin>>s;
getnex(s);
//cerr<<"!@3"<<'
';
int pos = nex[n];
string t = s;
k--;
//cerr<<"!@3"<<'
';
while(k--){
for(int i = pos;i<n;i++) t+=s[i];
}
cout <<t<<'
';
return 0;
}
B.
题意:给你一个长度n(2e5)的递增数组,让你找一个子串,它的2*ai>=ai+1。
思路:On的跑一遍,满足条件cnt++,此外cnt=0。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
int main(){
IO;
int n;cin>>n;
vector<int>a(n);
forn(i,n) cin>>a[i];
int cnt = 1,ans = 1;
for1(i,n-1){
if(a[i]<=a[i-1]*2) cnt++;
else cnt = 1;
ans = max(ans,cnt);
}
cout << ans <<'
';
return 0;
}
C
题意:给你n(2e5)个区间,让你删掉一个区间,使得区间重合部分最大。
思路:用multiset
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
int main(){
IO;
int n;cin>>n;
vector<pair<int,int> >a(n);
multiset<int>l,r;
forn(i,n){
cin>>a[i].first>>a[i].second;
l.insert(a[i].first);
r.insert(a[i].second);
}
int ans = 0;
forn(i,n){
l.erase(l.find(a[i].first));
r.erase(r.find(a[i].second));
int x = *l.rbegin(),y = *r.begin();
ans = max(ans,y-x);
l.insert(a[i].first);
r.insert(a[i].second);
}
cout << ans <<'
';
return 0;
}
D
题意:给你n个数(2e5),和一个k(1e9)。现在让你将任意两个数组合,比如12和23可以组合成1223和2312,如果组合过的数可以整除k,那么算是一个好数。看有多少个好数。
思路:很显然一个组合有数x10^leny
和y组成,那么只要知道x10^leny的余数和y的余数相加是否为0或k就可以。
预处理每个数字*10^(1-10)的余数,然后对应加起来。坑点比较多。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
map<ll,int>b[15];
int main(){
IO;
int n,k;cin>>n>>k;vector<int>a(n);
forn(i,n){
cin>>a[i];
ll x = a[i];
for1(j,10){
x*=10;
x%=k;
b[j][x]++;
//cerr<<x<<' '<<y<<'
';
}
}
ll ans = 0;
forn(i,n){
int len = 0,x = a[i];
while(x){
x/=10;
len++;
}
x = a[i]%k;
int y = k-x;
y%=k;
ans+=b[len][y];
ll z = a[i];
while(len--){
z*=10;
z%=k;
}
x = z%k;
if(x==y) ans--;
}
cout << ans <<'
';
return 0;
}
E
题意:给一棵树,n个点,n-1条边每个边权值为1。现在添加k条边使得所有点与1点距离小于等于2,求k的最小值。(n1e5)
思路:贪心 每次取距离1点最长距离点的父亲节点与1相连。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn = 2e5+5;
int ans;
vector<int>e[maxn],dis(maxn);
int dfs(int u,int pre,int d){
dis[u] = d;
bool ok = 0;
for(auto x:e[u]){
if(x==pre) continue;
dfs(x,u,d+1);
if(dis[x]>2){
ok = 1;
dis[u] = 1;
dis[pre] = 2;
}
}
ans+=ok;
}
int main(){
IO;
int n;cin>>n;
forn(i,n-1){
int x,y;cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,1,0);
for1(i,4)cerr<<dis[i]<<' ';
cerr<<'
';
cout << ans<<'
';
return 0;
}
F
题意:给你a个红色砖块和b个蓝色砖块,要求用完a和b拼成一个长方形(可以是正方形),并且满足里面的仅由红色砖或蓝色砖可组成一个矩形。求此矩形的最小周长。
思路:根号下枚举a,b和大矩形的宽。通过大矩形宽来找a或b中满足条件的最大宽(logn可以优化为On),然后记录一次ans,取最小。在来找最大宽的时候,我们可以根据上一次的结论来确定的新的最大宽为多少。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(ll i=0;i<n;i++)
#define for1(i,n) for(ll i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
int main(){
IO;
ll a,b;cin>>a>>b;
ll n = sqrt(a),m = sqrt(b);
vector<int>aa,bb;
for1(i,n)if(a%i==0) aa.push_back(i);
for1(i,m)if(b%i==0) bb.push_back(i);
ll sum = a+b;int x = sqrt(sum);
ll ans = 0x3f3f3f3f3f3f3f3f;
int p1,p2;p1 = p2 = 0;
for1(h,x)if(sum%h==0){
ll w = sum/h;
while(p1<aa.size()&&aa[p1]<=h)p1++;
while(p2<bb.size()&&bb[p2]<=h)p2++;
if(p1&&a/aa[p1-1]<=w) ans = min(ans,2*(h+w));
if(p2&&b/bb[p2-1]<=w) ans = min(ans,2*(h+w));
}
cout << ans<<'
';
return 0;
}