【解题报告】CF DIV2 #ROUND 707 A~C
比赛链接
半夜开比赛容易吵到室友所以以后开虚拟场了,这场还好没有贪心没在前3题,对我这种蒟蒻来说再好不过了。虽然还是只过了两题,不过A的还算快刚开始冲了一波2000名,然后卡死在第三题。
A.Alexey and Train
思路
模拟题,没啥好说的,看懂题目就可以了
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
/*DATA & KEY
t 1-100
n 1-100
a 1-1e6
tm 0-1e6
*/
int T;
const int N=105;
LL a[N],b[N],t[N];
void solve(int T)
{
//NEW DATA CLEAN
//NOTE!!!
LL n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
for(int i=1;i<=n;i++)cin>>t[i];
LL arrive=0,depart=0,remain=0;
for(int i=1;i<=n;i++)
{
arrive=depart+a[i]-b[i-1]+t[i];
remain=(b[i]-a[i]+1)/2;
depart=max(b[i],arrive+remain);
}
cout<<arrive<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
B.Napoleon Cake
思路
差分数组维护修改即可,不过注意可能超过边界即可
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
/*DATA & KEY
t 1 2e4
total n 1 2e5
ai 0 n
*/
int T;
const int N=2e5+10;
int d[N];
void solve(int T)
{
//NEW DATA CLEAN
memset(d,0,sizeof d);
//NOTE!!!
int n;cin>>n;
for(int i=1,x;i<=n;i++)
{
cin>>x;//i-x+1~i
d[max(1,i-x+1)]++;//max边界处理
d[i+1]--;
}
int ans=0;
for(int i=2;i<=n+1;i++)
{
ans+=d[i-1];
if(ans>0)cout<<1<<" ";
else cout<<0<<" ";
}
puts("");
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
C.Going Home
题意
给最多2e5个数,每个数保证小于2.5*1e6问有没有符合
a
[
x
]
+
a
[
y
]
=
a
[
w
]
+
[
z
]
a[x]+a[y]=a[w]+[z]
a[x]+a[y]=a[w]+[z]的四个不同的下标,
思路
这题比较有意思。原本以为二分+双指针什么的来优化,但是算来算去一直是时间复杂度爆炸的。
看了题解发现这玩意直接暴力出奇迹(没错,朴素的循环),不过暴力是有数学依据的:依据是鸽巢原理。
因为每个数保证小于
2.5
∗
1
e
6
2.5*1e6
2.5∗1e6的,所以和最大也只有
5
e
6
5e6
5e6,也就是说如果用map存下来的话是很容易发生冲突碰到和相同的。时间复杂度约为
O
(
m
i
n
(
n
2
,
5
e
6
)
)
O(min(n^2,5e6))
O(min(n2,5e6)),直接暴力就完事了。
然而这玩意即使知道了这个也挺卡时间的hh
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int>PII;
/*DATA & KEY
n 4 2e5
ai 1 2.5*1e6
*/
int T;
const int N=2e5+10,M=5e6+10;
int a[N];
PII mp[M];
bool vis[M];
void solve()
{
//NEW DATA CLEAN
//NOTE!!!
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int v=a[i]+a[j];
if(vis[v])
{
int x=mp[v].first,y=mp[v].second;
if(x!=i&&y!=j&&x!=j&&y!=i)
{
puts("YES");
printf("%d %d %d %d\n",i,j,x,y);
return;
}
}
else
{
mp[v]={i,j};
vis[v]=1;
}
}
puts("NO");
}
int main()
{
solve();
return 0;
}
一个代码优化的点 , 别用stl用成憨憨了啊!
map<Type,int>mp/unordered_map<Type,int>mp
如果数据量小的话就直接用Type mp[N]
顺便map的count和find找的是key而不是对应的值
反思
A:
多模拟样例,自己造样例
B:
差分数组这种修改操作记得处理超过边界的非正常情况
C:
问一堆数字里是否能找出k个数满足一个等式。除了双指针,二分还要想到鸽巢原理+暴力。总之如果想不到策略那就来一发朴素暴力呗。暴力出奇迹!