The 13th Chinese Northeast Collegiate Programming Contest
題目列表
- B - Balanced Diet
- C - Line-line Intersection
- E - Minimum Spanning Tree
- G - Radar Scanner
- H - Skyscraper
- J - Time Limit
Practice link:https://vjudge.net/contest/392938#overview
B - Balanced Diet
題意: 給你m種食物,給你1~m個L[i]表示如果你要取第i種食物,你至少要取L[i]個。再給你n個食物,有n個a[i]和b[i]分別表示食物的價值和種類,設U為食物的總價值,V為所有種類的食物中數量最大的種類的數量,問U/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 組隊訓練