【Codeforces】#Round495 Div2

本文详细解析了Codeforces Round 495 Div. 2比赛中的六道题目,从简单的酒店选择问题到复杂的矩阵操作及图论问题,覆盖了数据结构、算法优化等多个方面。

传送门:CodeforcesRound495Div2


A. Sonya and Hotels

这题没啥说的,就是int爆了要用long long

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int ans;
ll n,a[102],d;

int main(){
    ll i,j,q;
    scanf("%I64d%I64d",&n,&d);
    for(i=1;i<=n;++i)scanf("%I64d",&a[i]);
    sort(a+1,a+n+1);
    ans=2;
    for(i=1;i<n;++i){
        j=a[i]+d;
        if(a[i+1]>=j+d) ans++; 
        q=a[i+1]-d;
        if(q>a[i]+d) ans++;
    }
    printf("%d",ans);
}

B. Sonya and Exhibition

看题一脸懵逼??这是个B???
切完C才反应过来:
不管怎样增加区间要求,我们只要01间隔轮流摆总是没错的…
跪在b题,还是我太菜

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,i;
int main(){
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i) scanf("%d%d",&x,&y);
    for(i=1;i<=n;++i) printf("%c",'0'+(i&1));
}

C. Sonya and Robots

离散化一下,标记一下每个值第一次和最后一次出现的位置,指针扫一遍即可。
同样注意用long long

include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int n,v[N],z[N],f[N],a[N],b[N],cnt;
ll ans;

inline bool cmp(const int &x,const int &y){return z[v[x]]<z[v[y]];}
inline bool cmq(const int &x,const int &y){return f[v[x]]<f[v[y]];}

int main(){
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        scanf("%d",&a[i]);
        if(!z[a[i]]) z[a[i]]=i;
        f[a[i]]=i;
    }
    sort(a+1,a+n+1);v[++cnt]=a[1];
    for(i=2;i<=n;++i){
        if(a[i]!=a[i-1]){
            v[++cnt]=a[i];
        }
    } 
    for(i=1;i<=cnt;++i) a[i]=b[i]=i;
    sort(a+1,a+cnt+1,cmp);sort(b+1,b+cnt+1,cmq);
    for(j=1,i=1;i<=cnt;++i){
        while(f[v[b[j]]]<=z[v[a[i]]] && j<=cnt) 
        ++j;
        ans+=(cnt-j+1);
    }
    printf("%I64d",ans);
}

D. Sonya and Matrix

这题挺有意思的.
感觉把图旋转一下也没有什么区别。所以随便找一个x最小的答案就好啦。
可以发现,找到值最小的数 i(i>0) i ( i > 0 ) 且i的出现次数小于4*i次,这个i就等于0的x坐标。
同样假设可以把整个矩形分成左上左下右上右下四块,强行让0在右下这块,那么离它最远的必然是左上角的点,也就是数组里的最大值,设为 b=m+nxy b = m + n − x − y
(x,y) ( x , y ) 离右下角的距离 a=x+y2 a = x + y − 2
然后就枚举t的因数即枚举n,m的值,此时知道了 n,m,b,x n , m , b , x y y 由上面等式自然就推出来了,于是暴力O(t)算一遍这个数组,和原数组比较。
这个复杂度… n n 的枚举还套上 nlogn n log ⁡ n 的排序和有常数的枚举。
总之cf评测机能过

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int t,q[N],b,a,m,n,x,y,res[N],cnt;

inline void check()
{
    if((a>b) || (a<0) || (y<0)) return;\
    if((!(n&1) && n<x*2) || ((n&1) && n+1<x*2)) return;
    if((!(m&1) && m<y*2) || ((m&1) && m+1<x*2)) return;
    int i,j;cnt=0;
    for(i=1;i<=n;++i)
      for(j=1;j<=m;++j)
      {res[++cnt]=abs(i-x)+abs(j-y);}
    sort(res+1,res+t+1);
    for(i=1;i<=t;++i) if(res[i]!=q[i]) return;
    printf("%d %d\n%d %d",n,m,x,y);exit(0);
}

int main(){
    int i,j;
    scanf("%d",&t);
    for(i=1;i<=t;++i) scanf("%d",&q[i]);
    if(t==1){
       if(q[1]==0) printf("1 1\n1 1\n");
       else printf("-1\n");
       return 0;
    }
    sort(q+1,q+t+1);
    for(i=2;i<=t;i=j+1){
        for(j=i;q[j+1]==q[i] && j<t;++j);
        if((j-i+1)!=4*q[i]){x=q[i];break;}
    }
    b=q[t];
    for(i=1;i*i<=t;++i) if(t%i==0){
        n=i;m=t/i;y=m+n-b-x;
        a=m+n-b-2;check();
        if(i*i!=t){swap(m,n);check();}
    }
    printf("-1\n");
}

E. Sonya and Ice Cream

这题的贪心也很有意思。
可以肯定这样一条长度不超过k-1的链必然是直径上的一段子序列
不详说,很好证明。
那么就先找出最长链建两个指针分别指向链的两个端点,不断向内跳直到长度不超过k-1。而且可以肯定,当长度不超过k-1时, len=min(diameter,k1) l e n = m i n ( d i a m e t e r , k − 1 ) 一定能使答案最优。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int mx[N],f[N],dis[N];
int n,k,rt,dt,hd,tl,d[N],in[N];
int head[N],to[N<<1],nxt[N<<1],w[N<<1],tot;
int son[N];

inline void lk(int u,int v,int c)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=c;}

inline void dfs(int x)
{
    int i,j,mx1=x,mx2=x;mx[x]=x;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];if(j==f[x]) continue;
        f[j]=x;d[j]=d[x]+1;dis[j]=dis[x]+w[i];dfs(j);
        if(dis[mx[j]]>dis[mx1]){
            mx2=mx1;mx1=mx[j];
        }else if(dis[mx[j]]>dis[mx2]){
            mx2=mx[j];
        }
    }
    mx[x]=mx1;if(dis[mx1]+dis[mx2]-2*dis[x]>dt){
        dt=dis[mx1]+dis[mx2]-2*dis[x];
        hd=mx1;tl=mx2;rt=x;
    }
}

inline void df(int x)
{
    int i,j;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];if(j==f[x]) continue;
        if(in[x] && in[j]) son[x]=j;
        f[j]=x;d[j]=d[x]+1;dis[j]=dis[x]+w[i];
        df(j);  
    }
}

inline void dfss(int x)
{
    int i,j;mx[x]= in[x]? 0:x;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];if(j==f[x]) continue;
        dis[j]=dis[x]+w[i];f[j]=x;dfss(j);
        if(dis[mx[j]]>dis[mx[x]]) mx[x]=mx[j];
    }
    if(in[x]) {dt=max(dt,dis[mx[x]]-dis[x]);mx[x]=0;}
}

int main(){
    int i,j,ix,iy,iz,upl,upr,l=0,r=0,sonl,sonr;
    scanf("%d%d",&n,&k);
    for(i=1;i<n;++i){
      scanf("%d%d%d",&ix,&iy,&iz);
      lk(ix,iy,iz);lk(iy,ix,iz);
    }
    dfs(1);
    for(i=hd;i!=rt && f[i]!=rt;i=f[i]) in[i]=1;
    if(f[i]==rt) sonl=i,in[i]=1;
    for(i=tl;i!=rt && f[i]!=rt;i=f[i]) in[i]=1;
    if(f[i]==rt) sonr=i,in[i]=1;
    in[rt]=1;
    ix=d[hd]+d[tl]-2*d[rt]-k+1;
    f[rt]=0;d[rt]=0,dis[rt]=0;df(rt);
    upl= (d[hd]>d[rt]);upr=(d[tl]>d[rt]);
    for(;ix>0;ix--){
        if(upl) i=-(dis[f[hd]]-dis[hd]);
        else i= hd==rt?-(dis[rt]-dis[sonr]):-(dis[hd]-dis[son[hd]]);
        if(upr) j=-(dis[f[tl]]-dis[tl]);
        else j= tl==rt?-(dis[rt]-dis[sonl]):-(dis[tl]-dis[son[tl]]);
        if(l+i<=j+r){
          l+=i;in[hd]=0;if(upl) hd=f[hd];else hd= rt==hd? sonr:son[hd];
          if(hd==rt) upl=0;
        }else{
          r+=j;in[tl]=0;if(upr) tl=f[tl];else tl= rt==tl? sonl:son[tl];
          if(tl==rt) upr=0;
        }
    }
    dt=0;dis[hd]=0;f[hd]=0;dfss(hd);
    printf("%d\n",dt);
}

F. Sonya and Bitwise OR

先留个坑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值