崩了呀,做的心态爆炸,原本是昨天晚上开做的,A题字符串循环节,我最不擅长的就是循环节了,再加上当时脑子抽抽??A不会做,我都不敢信,然后后面的题目一个看不懂,A题交个标程,睡觉,心态爆炸。第二天,看A,暴力啊,直接暴力啊,然后过了,再看B,简单如斯,看我三分钟提交AC,嗯,然后WA了,然后发现自己看错题了,真的惨,还好还是简单。
C题不会,真心不会那种,后来看了标程,才发现自己题意又读错了,让求的是所有线段的交叉部分最大值,不是其中一部分的交叉部分最大值,我选择死亡··自己如果能读懂题的话,这题还是不难的。
D题真魔鬼啊,我第一次做的时候,思路正确,细节没处理好,WA了,好,我改,爆LL了???好,我改,改成ULL,因为我用的桶标记,还挺害怕MLE的,然后TLE on 28了。我?????好,cin改成scanf,map嵌套map改成map内部+pair,然后还是TLE on 28,改成unordered_map,哈哈哈哈,TLE on 56,这就nm离谱,我复杂度怎么算都不应该T啊,n10log(n)啊,然后看标程思路一致,但是人家不是桶,是直接二分查找,然后300ms+过了,留下我一个人风中凌乱。
E题看起来挺害怕的,其实就是贪心,每次连离自己最远的点。看了标程感觉不难,奈何心态爆炸,当时我绝对做不出来。
F题真心不难呐,原本以为是统计种类一类的,情况分类超恶心那种,看标程,因为是整数,所以从因数入手,学到了学到了,受益匪浅。
CDEF直接上标程了
A
这题还有o(n)的做法,奈何没看懂,可能是找循环节的简便算法,比如马拉车算法吧。
#include <iostream>
using namespace std;
int main()
{
int n,m; cin>>n>>m;
string a; cin>>a;
string base;
for(int i=0;i<int(a.size());i++){
base+=a[i];
string temp;
for(int j=0;j<m-1;j++){
temp+=base;
}
temp+=a;
int cnt=0;
for(int j=0;j<int(temp.size());j++){
if(a==temp.substr(j,int(a.size())))
cnt++;
}
if(cnt==m){
cout<<temp<<endl;
break;
}
}
return 0;
}
B
#include <iostream>
#include <algorithm>
using namespace std;
const int N=2e5+10;
int a[N];
int main()
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
int res=1,temp=1;
for(int i=1;i<n;i++){
if(a[i]<=2*a[i-1]){
temp++;
}
else{
temp=1;
}
res=max(res,temp);
}
cout<<res<<endl;
return 0;
}
C
#include <bits/stdc++.h>
#define forn(i, n) for (int i = 0; i < int(n); i++)
/*
n条线段的共用交错长度 = maxl-minr
然后枚举被去掉的那条线段
*/
using namespace std;
const int N = 300 * 1000 + 13;
const int INF = int(1e9);
int n;
int prl[N], prr[N], sul[N], sur[N];
int l[N], r[N];
int main() {
scanf("%d", &n);
forn(i, n)
scanf("%d%d", &l[i], &r[i]);
prl[0] = sul[n] = 0;//l的最大值
prr[0] = sur[n] = INF;//r的最小值
forn(i, n){//l的最大值和r的最小值
prl[i + 1] = max(prl[i], l[i]);
prr[i + 1] = min(prr[i], r[i]);
}
for (int i = n - 1; i >= 0; --i){
sul[i] = max(sul[i + 1], l[i]);
sur[i] = min(sur[i + 1], r[i]);
}
int ans = 0;
forn(i, n)
ans = max(ans, min(prr[i], sur[i + 1]) - max(prl[i], sul[i + 1]));
printf("%d\n", ans);
return 0;
}
D
#include <bits/stdc++.h>
#define forn(i, n) for (int i = 0; i < int(n); i++)
typedef long long li;
using namespace std;
const int N = 200 * 1000 + 13;
const int LOGN = 11;
int n, k;
int a[N];
int len[N];
vector<int> rems[LOGN];
int pw[LOGN];
int main() {
scanf("%d%d", &n, &k);
forn(i, n) scanf("%d", &a[i]);
pw[0] = 1;//预处理10的幂次
forn(i, LOGN - 1)
pw[i + 1] = pw[i] * 10 % k;
forn(i, n){
int x = a[i];
while (x > 0){//处理a[i]的位数
++len[i];
x /= 10;
}
rems[len[i]].push_back(a[i] % k);
}
forn(i, LOGN)
sort(rems[i].begin(), rems[i].end());//把当前长度的余数 排序
li ans = 0;
forn(i, n){//数字a[i]在前
for (int j = 1; j < LOGN; ++j){//假设后半部分长度为j
int rem = (a[i] * li(pw[j])) % k;
int xrem = (k - rem) % k;
auto l = lower_bound(rems[j].begin(), rems[j].end(), xrem);
auto r = upper_bound(rems[j].begin(), rems[j].end(), xrem);
ans += (r - l);
if (len[i] == j && (rem + a[i] % k) % k == 0)
--ans;
}
}
printf("%lld\n", ans);
return 0;
}
E
#include <bits/stdc++.h>
using namespace std;
const int N = 200 * 1000 + 11;
int p[N];//记录父节点 parent
int d[N];//记录和根节点的距离
vector<int> g[N];//存图
void dfs(int v, int pr = -1, int dst = 0) {//当前节点,父节点,与根节点的距离
d[v] = dst;
p[v] = pr;
for (auto to : g[v]) {
if (to != pr) {
dfs(to, v, dst + 1);
}
}
}
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
for (int i = 0; i < n - 1; ++i) {
int x, y;
scanf("%d %d", &x, &y);
--x, --y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(0);
set<pair<int, int>> st;//存距离大于2的节点
for (int i = 0; i < n; ++i) {
if (d[i] > 2) {
st.insert(make_pair(-d[i], i));//set内的pair按照1.第一关键字和2.第二关键字排序
}
}
int ans = 0;
while (!st.empty()) {//找距离最大的点
int v = st.begin()->second;//当前节点
v = p[v];//自己的父节点
++ans;
auto it = st.find(make_pair(-d[v], v));
if (it != st.end()) {//消去父节点
st.erase(it);
}
for (auto to : g[v]) {//消去自己和所有与自己同级的
auto it = st.find(make_pair(-d[to], to));
if (it != st.end()) {
st.erase(it);
}
}
}
printf("%d\n", ans);
}
F
#include <bits/stdc++.h>
#define forn(i, n) for (int i = 0; i < int(n); i++)
typedef long long li;
using namespace std;
const int N = 1000 * 1000;
int lens[N];
int k;
li solve(li a, li b){
k = 0;
for (li i = 1; i * i <= b; ++i)//找到b的所有因子
if (b % i == 0)
lens[k++] = i;
li ans = 2 * (a + b) + 2;
li x = a + b;
int l = 0;
for (li i = 1; i * i <= x; ++i){
if (x % i == 0){//面积的因子i 也就是矩形的长
while (l + 1 < k && lens[l + 1] <= i)//找到最后一个小于i的因数作为自己的短边
++l;
//略过的部分更容易构成扁的矩形 面积一定时,长和宽越接近,周长越短
if (b / lens[l] <= x / i)
ans = min(ans, (i + x / i) * 2);
}
}
return ans;
}
int main() {
li a, b;
scanf("%lld%lld", &a, &b);
printf("%lld\n", min(solve(a, b), solve(b, a)));
return 0;
}