The 13th Chinese Northeast Collegiate Programming Contest

题目列表


B - Balanced Diet

题意: 给你m种食物,给你1~m个L[i]表示如果你要取第i种食物,你至少要取L[i]个。再给你n个食物,有n个a[i]和b[i]分别表示食物的价值和种类,设U为食物的总价值,V为所有种类的食物中数量最大的种类的数量,问U/V的最大值是多少。
思路:首先我们看取某种食物的顺序,因为U越大越好,因此每类食物都要从大到小排序,然后枚举每个分母V的值,那么分母U的值也就是在符合L[i]的前提下取第i种食物的前V项即可。
代码:

‘’‘’‘’
const int maxn = 100005;
inline ll gcd(ll a,ll b) {
    return b>0 ? gcd(b,a%b):a;
}
struct node{
    int l,id;
}ss[maxn];
int n,m;
vector<int>swt[maxn];
vector<int>sum[maxn];
bool cmp(int x,int y)
{
    return x>y;
}
int main()
{
    int T;
    cin>>T;
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=max(n,m);i++){
            swt[i].clear();
            sum[i].clear();
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&ss[i].l);
            ss[i].id=i;
        }
        for(int i=1;i<=n;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            swt[y].push_back(x);
        }
        for(int i=1;i<=m;i++){
            sort(swt[i].begin(),swt[i].end(),cmp);
      for(int j=0;j<swt[i].size();j++){
                sum[max(j+1,ss[i].l)].push_back(swt[i][j]);
            }
        }
        ll mm=0,zz=0,nm=1,nz=0;
        for(int i=1;i<=n;i++){
            mm=i;
        for(int j=0;j<sum[i].size();j++){
                zz+=sum[i][j];
          }
            f(1ll*nm*zz>1ll*nz*mm){
                nm=mm;
                nz=zz;
            }
        }
        ll pp=gcd(nz,nm);
      printf("%lld/%lld\n",nz/pp,nm/pp);
    }
    return 0;
 }


C - Line-line Intersection

思路:两条直线不平行则必相交,若平行:若相交那么答案+1,否则不算。两个map去储存,第一个map储存某一斜率下平行的数量,第二个map储存某一条直线的重合数量。在添加第i条直线时,答案ans=i-平行数量+重合数量。
代码:

‘’‘’‘’
map<pair<ll,ll>,ll>k;
map<pair<pair<ll,ll>,ll>,ll>c;
int main()
{
    int n,t;
    t=read();
    while(t--)
    {
        n=read();
        ll ans=0;
        k.clear();
        c.clear();
        for(int i=0;i<n;i++)
        {
            ll x1,y1,x2,y2,x;
            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
            x=x1*y2-x2*y1;
            ll xx=x2-x1;
            ll yy=y2-y1;
            ll d=__gcd(xx,yy);
            xx/=d;
            yy/=d;
            x/=d;
            ans+=i-k[{xx,yy}]+c[{{xx,yy},x}];
            k[{xx,yy}]++;
            c[{{xx,yy},x}]++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

E - Minimum Spanning Tree

题意:给你一幅图,把边看成点,有公共点的两条边就是有一条连边的两个点,边权就是两条边的边权之和,让你构造一颗最小生成树,问你边权之和是多少。
思路:我们从每条边的贡献入手,显然,一个点的所有出边中,我们要用到最多的就是最小边,最小边要和可以和它相连的所有边相连,则其贡献就是(出边数-1)*w,对于其它边,要保证连通,都会用到一次。
代码:

vector<ll>g[maxn];
int main()
{
    ll T,n;
    cin>>T;
    while(T--){
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            g[i].clear();
        }
        for(int i=1;i<n;i++){
            ll u,v,w;
            scanf("%lld %lld %lld",&u,&v,&w);
            g[u].push_back(w);
            g[v].push_back(w);
        }
        ll ans=0;
        ll res=0;
        ll minn=INF;
        for(int i=1;i<=n;i++){
            res=0;
            minn=INF;
            if(g[i].size()<=1)continue;
            for(int j=0;j<g[i].size();j++){
                ll u=g[i][j];
                res+=u;
                minn=min(minn,u);
            }
            res+=(g[i].size()-2)*minn;
            ans+=res;
        }
        printf("%lld\n",ans);
    }
    return 0;
 }

G - Radar Scanner

题意:在二维平面上,给你n个矩形的左下角和右上角坐标,一次移动可以选择一个矩形向上下左右移动一格。问你最少多少次移动可以让所有矩形有一个公共相交点。
思路:首先是二维平面上的问题,且相互独立,那么可以转化为一维问题。就是若干条直线,最少移动多少次有公共点。猜一下是移到所有点的中位数就是最小。
代码:

‘’‘’‘’
const int maxn = 100005;
vector<ll>g[maxn];
int main()
{
    ll T,n;
    cin>>T;
    while(T--){
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            g[i].clear();
        }
        for(int i=1;i<n;i++){
            ll u,v,w;
            scanf("%lld %lld %lld",&u,&v,&w);
            g[u].push_back(w);
            g[v].push_back(w);
        }
        ll ans=0;
        ll res=0;
        ll minn=INF;
        for(int i=1;i<=n;i++){
            res=0;
            minn=INF;
            if(g[i].size()<=1)continue;
            for(int j=0;j<g[i].size();j++){
                ll u=g[i][j];
                res+=u;
                minn=min(minn,u);
            }
            res+=(g[i].size()-2)*minn;
            ans+=res;
        }
        printf("%lld\n",ans);
    }
    return 0;
 }


H - Skyscraper

题意:n座摩天大楼,每座的预计层高为a[i]。
m次操作:
1、将a的某个区间[l , r]加上k。
2、询问仅对[l, r]区间从0开始施工,最少需 要几个阶段。
每一个阶段操作,可以任意选取一个区间,在这个区间上每个a[i]加上1 。
思路:
** 1、首先令b[I]=a[I]-a[i-1] 。
** 2、b[i]>0,那么要多花b[i]个阶段才能把a[i]修好。
** 3、b[i]<=0,那么在修a[i-1]时就可以把a[i]顺带着修好。
** 4、那么令c[I]=b[i] (b[ I]>0),就表示在修好i-1这个楼后要修i这个楼需要的阶段。
** 5、那么对于区间[l,r]需要的阶段就是a[l]+c[l+1]+c[l+2]+……+c[r-1]+c[r]。
** 6、也就是(b[1]+b[2]+……+b[l])+(c[l+1]+c[l+2]+……+c[r-1]+c[r])。
** 7、对于区间加的操作,我们只需要在b和c数组的l处加上k,r+1处减去k,即可。
** 8、用树状数组维护前缀和即可。
代码:

‘’‘’‘’
const int maxn = 100005;

ll a[maxn],b[maxn],c[maxn];
ll T,n,m;
struct tr{
    ll sum[maxn];
    void add(int p,ll x){
        while(p<=n){
            sum[p]+=x;
            p+=p&(-p);
        }
    }
    ll ask(int p){
        ll res=0;
        while(p){
            res+=sum[p];
            p-=p&(-p);
        }
        return res;
    }
    ll r_ask(int l,int r){
        return ask(r)-ask(l-1);
    }
}tb,tc;
int main()
{
    cin>>T;
    while(T--){
        for(int i=1;i<maxn;i++){
            tb.sum[i]=0;
            tc.sum[i]=0;
            b[i]=0;
        }
        scanf("%lld %lld",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            if(i>=2){
                b[i]=a[i]-a[i-1];
                tb.add(i, b[i]);
                if(b[i]>0){
                    tc.add(i, b[i]);
                }
            }else{
                b[i]=a[i];
                tb.add(i, a[i]);
                tc.add(i, a[i]);
            }
        }
        int op,l,r,x;
        while(m--){
            scanf("%d",&op);
            if(op==1){
                scanf("%d %d %d",&l,&r,&x);
                tb.add(l, x);
                tb.add(r+1,-x);
                if(b[l]>0){
                    tc.add(l, x);
                }else if(b[l]+x>0){
                    tc.add(l, b[l]+x);
                }
                if(b[r+1]>0){
                    if(b[r+1]-x>0){
                        tc.add(r+1, -x);
                    }else{
                        tc.add(r+1, -b[r+1]);
                    }
                }
                b[l]+=x;
                b[r+1]-=x;
            }else{
                scanf("%d %d",&l,&r);
                printf("%lld\n",tb.r_ask(1,l)+tc.r_ask(l+1,r));
            }
        }
    }
    return 0;
 }

J - Time Limit

代码:

‘’‘’‘’
#include<bits/stdc++.h>
using namespace std;
int t,a[1001],n;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int k=3*a[1];
       
        for(int i=2;i<=n;i++)
        {
           k=max(k,1+a[i]);
        }
        if(k%2==0) printf("%d\n",k);
        else printf("%d\n",k+1);
    }
    return 0;
}

记 2020 9.5 组队训练

posted @ 2020-09-06 15:40  hachuochuo  阅读(303)  评论(0编辑  收藏  举报