牛客网 长安大学第三届ACM-ICPC程序设计竞赛(同步赛)部分题解

A题

暴力计算时间即可.

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;
p operator +(const p &_,const p &__){
    p ret;
    ret.second=(_.second+__.second);
    ret.first=(_.first+__.first+ret.second/60)%24;
    ret.second%=60;
    return ret;
}
int main(){
    int t; scanf("%d",&t);
    while (t--){
        p t=p(12,0);
        int x;
        scanf("%d",&x);
        t=t+p(0,x);
        if (t.second>=10)
        printf("%d:%d\n",t.first,t.second);
        else 
        printf("%d:0%d\n",t.first,t.second);
    }
}
View Code

B题

计算概率分类讨论.

首先路程大于等于2圈肯定不行

一圈以内及一圈概率计算一波

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t; scanf("%d",&t);
    while (t--){
        int k,x; scanf("%d%d",&k,&x);
        if (k>=2*x) puts("0.00");
        else if (k<x){
            double in=1.*k/x,out=1-in;
            printf("%.2lf\n",in*in/2+in*out+out*in+out*out);
        }
        else{
            double in=1.*(k-x)/x,out=1-in;
            printf("%.2lf\n",out*out/2);
        }
    }
}
View Code

C题

二分答案,O(n)验证,小心边界问题

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,a[N],num,b[N];
long long k;
long long check(int x){
//    cerr<<"x"<<x<<endl;
    int j=n; long long tot=0;
    num=0;
    for (int i=n; i>=1; --i){
        if (a[i]>x) ++num;
        while (num>1&&j>i) num-=(a[j]>x),--j;
        tot+=j-i;
//        cerr<<"i j"<<i<<" "<<j<<" "<<num<<endl;
    }
//    cerr<<tot<<endl;
    return tot;
}
int main(){
    int t;
    scanf("%d",&t);
    while (t--){
        scanf("%d%lld",&n,&k);
        int ans=2333;
        for (int i=1; i<=n; ++i) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        for (int l=1,r=n,mid=(l+r)>>1; l<=r; mid=(l+r)>>1)
        if (1ll*n*(n-1)/2-check(b[mid])<k) ans=mid,r=mid-1; else l=mid+1;
        printf("%d\n",b[ans]); 
    }
}
View Code

D题

莫队算法(有信仰就能过)

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;
const int N=100010;
pair<p,int> a[N];
int n,m,s,q,an[N],num[N],fa[N],d[N];
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool cmp(const pair<p,int> &_, const pair<p,int> &__){
    return d[_.first.first]<d[__.first.first]||(d[_.first.first]==d[__.first.first]&&_.first.second<__.first.second);
}
int main(){
    int t; scanf("%d",&t);
    for (int i=1; i<=100000; ++i) d[i]=i/1000;
    while (t--){
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; ++i) fa[i]=i;
        for (int i=1; i<=m; ++i){
            int x,y; scanf("%d%d",&x,&y);
            x=find(x); y=find(y);
            if (x==y) continue;
            fa[x]=y;
        }
        scanf("%d",&q);
        for (int i=1; i<=q; ++i) scanf("%d%d",&a[i].first.first,&a[i].first.second),a[i].second=i;
        for (int i=1; i<=n; ++i) num[i]=0;
        for (int i=1; i<=n; ++i) find(i);
        sort(a+1,a+q+1,cmp);
        int l=1,r=0,ans=0;
        for (int i=1; i<=q; ++i){
            int ll=a[i].first.first,rr=a[i].first.second;
            while (r<rr){
                ++r;
                if (!num[fa[r]]++) ++ans;
            }
            while (r>rr){
                if (!--num[fa[r]]) --ans;
                --r;
            }
            while (l>ll){
                --l;
                if (!num[fa[l]]++) ++ans;
            }
            while (l<ll){
                if (!--num[fa[l]]) --ans;
                ++l;
            }
            an[a[i].second]=ans;
        }
        for (int i=1; i<=q; ++i) printf("%d\n",an[i]);
    }
}
View Code

E题

OEIS大法好(待研究)

#include<bits/stdc++.h>
using namespace std;
int f[100];
int main(){
    int t; scanf("%d",&t);
    f[1]=7; for (int i=2; i<=11; ++i) f[i]=f[i-1]*7/*,printf("%d\n",f[i])*/;
    while (t--){
        int x; scanf("%d",&x);
        printf("%.0Lf\n",2*ceil((long double)sqrt(12ll*x-3)));
    }
}
View Code

F题

貌似是一道codeforces原题,大佬讲过,未AC

G题

求树上某点出发最长链,再分类讨论.

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int ne[N<<1],fi[N],b[N<<1],k,dep[N],dis[N],n,q;
void add(int x,int y){
    ne[++k]=fi[x]; b[fi[x]=k]=y;
}
void dfs(int x,int fa,int deep){
    dep[x]=deep;
    dis[x]=max(dis[x],deep);
    for (int j=fi[x]; j; j=ne[j])
    if (b[j]!=fa) dfs(b[j],x,deep+1);
}
int main(){
    int t; scanf("%d",&t);
    while (t--){
        scanf("%d",&n);
        for (int i=1; i<=n; ++i) fi[i]=dep[i]=dis[i]=0; k=0;
        for (int i=1; i<n; ++i){
            int x,y; scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
        }
        dfs(1,0,0);
        int mx=1;
        for (int i=2; i<=n; ++i)
        if (dep[i]>dep[mx]) mx=i;
        dep[mx]=0;
        dfs(mx,0,0);
        int mxx=1;
        for (int i=2; i<=n; ++i)
        if (dep[i]>dep[mxx]) mxx=i;
        dep[mxx]=0;
        dfs(mxx,0,0);
        scanf("%d",&q);
        for (int i=1; i<=q; ++i){
            int x,y; scanf("%d%d",&x,&y);
//            cerr<<y-(n-dis[x]-1)*2<<" "<<dis[x]<<endl;
            if (dis[x]>=y){
                printf("%d\n",y+1);
//                cerr<<"dis"<<dis[x]<<" "<<y<<endl;
            }
            else if (y<=(n-dis[x]-1)*2){
                printf("%d\n",max(y/2+1,dis[x]+1));
//                cerr<<"2t"<<endl;
            }
            else printf("%d\n",max(dis[x]+1,(n-dis[x]-1)+1+y-(n-dis[x]-1)*2));
        }
    }
}
View Code

H题

两次01背包

#include <bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
const int N=1010;
int n,m,q;
int a[N],b[N],c[N],d[N],f[N],g[N+N];
int main(){
    int t; scanf("%d",&t);
    while (t--){
        scanf("%d",&n);
        int suma=0;
        for (int i=1; i<=n; ++i) scanf("%d%d",&a[i],&b[i]),suma+=a[i];
        scanf("%d",&m);
        for (int i=1; i<=m; ++i) scanf("%d%d",&c[i],&d[i]);
        scanf("%d",&q);
        for (int i=1; i<=1000; ++i) f[i]=INF;
        for (int i=1; i<=n; ++i)
        for (int j=1000; j>=b[i]; --j)
        f[j]=min(f[j-b[i]]+a[i],f[j]);
        for (int i=1; i<=2000; ++i) g[i]=0;
        for (int i=1; i<=m; ++i)
        for (int j=2000; j>=d[i]; --j)
        g[j]=max(g[j-d[i]]+c[i],g[j]);
        int ans=0;
        for (int i=0; i<=1000; ++i)
        ans=max(ans,suma-f[i]+g[i+q]);
        printf("%d\n",ans);
    }
}
View Code

I题

毫无想法

看起来是压轴题.(待研究)

J题

贪心的代码不懂

不过可以用带权最小路径覆盖做.

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<long long,long long> p;//?
const long double INF=1e11;
const int N=210;
struct edge{
    int y,cap;
    long double cost;
    int op;
    edge(int y,int cap,long double cost,int op):y(y),cap(cap),cost(cost),op(op){}
};
vector<edge> g[N<<1];
p prep[N<<1];
bool in[N<<1];
int a[N],b[N];
long double f[N<<1];
int n,m,s,t;
long double spfa(){
    queue<int> q;
    fill(f+s,f+t+1,INF);
    fill(in+s,in+t+1,0);
    f[s]=0; q.push(s); in[s]=1;
    while (!q.empty()){
        int x=q.front(); q.pop(); in[x]=0;
        for (size_t j=0; j<g[x].size(); ++j){
            edge e=g[x][j];
            if (e.cap&&f[e.y]>f[x]+e.cost){
                f[e.y]=f[x]+e.cost;
                prep[e.y]=p(x,j);
                if (!in[e.y]) q.push(e.y),in[e.y]=1;
            } 
        }
    }
    if (f[t]>=0) return -1;
    int that=INF;
    for (int i=t; i!=s; i=prep[i].first) that=min(that,g[prep[i].first][prep[i].second].cap);
    for (int i=t; i!=s; i=prep[i].first){
        edge &e=g[prep[i].first][prep[i].second];
        e.cap-=that;
        g[e.y][e.op].cap+=that;
    }
    return that*f[t];
}
bool init(int x,bool a,int y,bool b){
    if (a==b) return x>=y;
    if (a) return x>=(y<<1);
    return ((x*x)<<1)>=y*y;
}
void add(int x,int y,int cap,long double cost){
    g[x].push_back(edge(y,cap,cost,g[y].size()));
    g[y].push_back(edge(x,0,-cost,g[x].size()-1));
}
void myunique(int *r,int &len){
    sort(r+1,r+len+1);
    len=unique(r+1,r+len+1)-r-1;
}
signed main(){
    int ttt; scanf("%lld",&ttt);
    while (ttt--){
        scanf("%lld%lld",&n,&m);
        for (int i=1; i<=n; ++i) scanf("%lld",&a[i]);
        for (int i=1; i<=m; ++i) scanf("%lld",&b[i]);
        myunique(a,n); myunique(b,m);
        s=0; t=((n+m)<<1)+1;
        for (int i=s; i<=t; ++i) g[i].clear();
        for (int i=1; i<=n; ++i) add(s,i,1,a[i]*a[i]);
        for (int i=1; i<=m; ++i) add(s,n+i,1,acos(-1)*b[i]*b[i]);
        for (int i=1; i<=n+m; ++i) add(i,n+m+i,1,-INF),add(n+m+i,t,1,0);
        for (int i=1; i<=n+m; ++i)
        for (int j=1; j<=n+m; ++j)
        if (i!=j&&init(i<=n?a[i]:b[i-n],i<=n,j<=n?a[j]:b[j-n],j<=n)) add(n+m+i,j,1,0);
        long double t,ans=0; while ((t=spfa())!=-1) ans+=t;
        printf("%.2Lf\n",ans+(n+m)*INF);
    }
}
View Code

K题

仅有个位数的人过.不过我把另一个AC的叉掉了,我的复杂度为O(q*sqrt(n)*log(n))

此题数据范围有毒. a[i]<=n 不存在的.(p.s.此题暴力可以水过)

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
using namespace std;
const int N=20010,NODE=2000010;
vector<int> g[N];
struct node{int v,l,r;}T[NODE];
int ll,rr,sz,root[N],fi[N],ne[N<<1],b[N<<1],top[N],v[N],k,a[N],s,n,q,d;
map<int,int> mp;
void clear(){
    for (int i=1; i<=n; ++i) fi[i]=0;
    for (int i=1; i<=n; ++i) g[i].clear();
    mp.clear();
    k=sz=d=0;
}
void add(int x,int y){
    ne[++k]=fi[x]; b[fi[x]=k]=y;
}
void read(int &x){
    char ch=getchar(); x=0;
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
void init(){
    read(n); s=(int(sqrt(n))>>1)+1;
    for (int i=1; i<n; ++i){
        int x,y; read(x); read(y);
        add(x,y); add(y,x);
    }
    for (int i=1; i<=n; ++i) read(a[i]),mp[a[i]]=1;
    for (map<int,int>::iterator i=mp.begin(); i!=mp.end(); ++i) i->second=++d;
    for (int i=1; i<=n; ++i) g[a[i]=mp[a[i]]].push_back(i);
}
int ask(int ind,int l,int r){
    if (!ind) return 0;
    if (ll<=l&&r<=rr) return T[ind].v;
    int mid=(l+r)>>1,ret=0;
    if (ll<=mid) ret+=ask(T[ind].l,l,mid);
    if (mid<rr) ret+=ask(T[ind].r,mid+1,r);
    return ret;
}
void fork(int &ind,int pa,int l,int r){
    T[ind=++sz]=T[pa];
    if (l==r) return void(++T[ind].v);
    int mid=(l+r)>>1;
    ll<=mid?fork(T[ind].l,T[pa].l,l,mid):fork(T[ind].r,T[pa].r,mid+1,r);
    T[ind].v=T[T[ind].l].v+T[T[ind].r].v;
}
void add(int &ind,int l,int r){
    if (!ind) T[ind=++sz]=T[0];
    if (l==r) return void(T[ind].v+=rr);
    int mid=(l+r)>>1;
    ll<=mid?add(T[ind].l,l,mid):add(T[ind].r,mid+1,r);
    T[ind].v=T[T[ind].l].v+T[T[ind].r].v;
}
void build(int x,int fa){
    ll=a[x];
    fork(root[x],root[fa],1,d);
    for (int j=fi[x]; j; j=ne[j])
    if (b[j]!=fa) build(b[j],x);
}
void dfs(int x,int fa){
    v[x]=(a[x]==rr);
    for (int j=fi[x]; j; j=ne[j])
    if (b[j]!=fa){
        dfs(b[j],x);
        v[x]+=v[b[j]];
    }
}
void zig(int x){
    top[x]=0;
    rr=x; dfs(1,0);
    for (int i=1; i<=n; ++i){
        ll=a[i]; rr=v[i];
        if (rr) add(top[x],1,d);
    }
}
void solve(){
    build(1,0);
    for (int i=1; i<=d; ++i) if (g[i].size()>s) zig(i);
    read(q);
    while (q--){
        int x,k,y;
        read(x); read(k); y=x;
        if (mp.find(x)==mp.end()){putchar('0'); putchar('\n'); continue;} 
        x=mp[x]; ll=max(mp.lower_bound(y-k)->second,1); rr=min((--mp.upper_bound(y+k))->second,d);
        if (g[x].size()<=s){
            int ans=0;
            for (size_t j=0; j<g[x].size(); ++j) ans+=ask(root[g[x][j]],1,d);
            printf("%d\n",ans-g[x].size());
        }
        else printf("%d\n",ask(top[x],1,d)-g[x].size());
    }
}
int main(){
    int t; read(t);
    while (t--){
        init();
        solve();
        clear();
    }
}
View Code

L题

我wa了好几发.负进制搞一搞.

#include<bits/stdc++.h>
using namespace std;
int st[100];
int calc(int x){
    memset(st,0,sizeof(st));
    int top=0;
    for (int i=1; i<=4; ++i){
        st[++top]=x%9;
        x/=9;
        if (st[top]>=5){
            st[top]=st[top]-9;
            ++x;
        }
    }
    int ans=0;
    for (int i=1; i<=4; ++i) ans+=abs(st[i]);
    return ans+x;
}
int main(){
    int t;
    scanf("%d",&t);
    while (t--){
        int x; scanf("%d",&x);
        int t=1;
        int z=1e9+7;
        printf("%d\n",calc(x));
    }
}
View Code
posted @ 2018-04-15 22:11  Yuhuger  阅读(350)  评论(0编辑  收藏  举报