20201012sdssy考试
heaven_soar · · 个人记录
sdssy20201012
实际为USACO open20 silver
充分说明N老师对于USACO的喜爱程度
感觉t2t3都很有意思,思维难度大,代码简单
t1
水题,二分就完事了。
但我这个憨批忘了排序,交了很多遍没过。。。。
所以一定要仔细看题、仔细检查。抵制样例欺诈,从我做起
代码:
struct grass{
ll start,end;
}g[100010];
bool cmp(grass a,grass b){
return a.start<b.start;
}
int main(){
int n=qread(),m=qread();
for(re int i=1;i<=m;++i){
g[i].start=qread(),g[i].end=qread();
}
sort(g+1,g+1+m,cmp);
ll lst=0,l=0,r=g[m].end,mid;
while(l<r){
mid=(l+r+1)>>1;
int tm=1,pos=1;
lst=g[1].start;
while(lst<=g[m].end&&pos<=m){
if(lst+mid>=g[pos].start&&lst+mid<=g[pos].end) tm++,lst+=mid;
else if(lst+mid>g[pos].end) pos++;
else if(lst+mid<g[pos].start)lst=g[pos].start,tm++;
}
if(tm>=n) l=mid;
else r=mid=mid-1;
}
cout<<mid<<'\n';
return 0;
}
t2
两种方法,队列维护或 抢麦子吃 从后向前扫。
队列的方法暂时没调出来,这里只放抢麦反向扫法:
int ans[100010],cnt=0,eat[100010],f[100010],s[100010];
void solve(int x,int y){//x是当前牛编号,y是麦片编号
if(!eat[y]){
eat[y]=x;
cnt++;
return;
}
if(eat[y]>x){
int z=eat[y];
eat[y]=x;
if(y==f[z]) solve(z,s[z]);
}
}
int main(){
int n=qread(),m=qread();
for(re int i=1;i<=n;++i){
f[i]=qread(),s[i]=qread();
}
for(re int i=n;i>=1;--i){
solve(i,f[i]);
ans[i]=cnt;
}
for(re int i=1;i<=n;++i){
cout<<ans[i]<<'\n';
}
return 0;
}
t3
这道题转化很多:
- 每一组
(x,y) 看做平面上一点
- 对于每个点,左下和右上方的点与其在同一连通块中,可以连边用并查集维护森林,结论即有多少棵树,复杂度
O(n^2) 过不了。 - 其实可以维护前缀最小值和后缀最大值,对于一个点,它及前面的点的最小值大于它后面点的最大值,它就是反应完剩下的那个点,除sort外
O(n)
代码:
struct node{
int x,y;
}nd[100010];
bool cmp(node a,node b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
int mn[100010],mx[100010];
int Max(int x,int y){
return x>y?x:y;
}
int Min(int x,int y){
return x<y?x:y;
}
int main(){
int n=qread();
for(re int i=1;i<=n;++i){
nd[i].x=qread(),nd[i].y=qread();
}
sort(nd+1,nd+1+n,cmp);
mn[1]=nd[1].y;
for(re int i=2;i<=n;++i)
mn[i]=Min(mn[i-1],nd[i].y);
mx[n]=nd[n].y;
for(re int i=n-1;i>=1;--i)
mx[i]=Max(mx[i+1],nd[i].y);
int ans=1;
for(re int i=1;i<=n;++i){
if(mn[i]>mx[i+1]) ans++;
}
cout<<ans<<'\n';
return 0;
}