2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)(solve7/11)
阿新 • • 發佈:2018-12-14
B題
題意:給你n個人的第一棒的速度和其他棒的速度,然後讓你輸出最快的那個組合,輸出時間和人。
思想:模擬
D題
題意:給你n個01串代表每個人的特徵,現在讓你求一個和他們長度相等但是和他們相似度最對的那個串。
思想:考慮最短路問題,將每個串拆出來k個差一位的子串,然後每個串開始不斷的取反某一位,最後找到一個取反最多的。輸出即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+5; char str[30]; int dist[1<<20]; int main() { queue<int>q; memset(dist,-1,sizeof(dist)); int n,k; scanf("%d%d",&n,&k); for(int i=0;i<n;i++) { scanf("%s",str); int ans=0; for(int i=0;i<k;i++) if(str[i]=='1') ans=ans+(1<<i); q.push(ans); dist[ans]=0; } int ans=0; int maxx=0; while(!q.empty()) { int temp=q.front(); q.pop(); for(int i=0;i<k;i++) { int T = temp^(1<<i); if(dist[T]!=-1) continue; q.push(T); dist[T]=dist[temp]+1; if(dist[T]>maxx) { maxx=dist[T]; ans=T; } } } for(int i=0;i<k;i++) { if(ans&(1<<i)) printf("1"); else printf("0"); } printf("\n"); return 0; }
E題
題意:給你一個n*m的圖,每個點有一個權值 小於0為水高於0為乾旱的地,現在將抽水機放到一個位置問你最多能抽多少水,直接bfs抽水機的點,比當前點小的變到跟當前一樣大,因為最多抽到跟當前點一樣多的水。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e2+10; int vis[maxn][maxn]; ll Map[maxn][maxn]; ll dis[maxn][maxn]; int dir[8][2]={-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1}; struct node{ int x; int y; ll valu; bool operator <(const node &a) const{ return valu > a.valu; } }; int main() { int h,w; int x,y; scanf("%d%d",&h,&w); for(int i=1;i<=h;i++) for(int j=1;j<=w;j++) scanf("%lld",&Map[i][j]); scanf("%d%d",&x,&y); priority_queue<node>q; q.push(node{x,y,Map[x][y]}); vis[x][y]=1; dis[x][y]=Map[x][y]; while(!q.empty()) { node u=q.top(); q.pop(); for(int i=0;i<8;i++) { int xx=dir[i][0]+u.x; int yy=dir[i][1]+u.y; if(xx>=1 && xx<=h && yy>=1 && yy<=w && vis[xx][yy]==0 && Map[xx][yy] < 0) { vis[xx][yy]=1; ll T = max(u.valu,Map[xx][yy]); dis[xx][yy]=T; q.push(node{xx,yy,T}); } } } ll ans=0; for(int i=1;i<=h;i++) for(int j=1;j<=w;j++) ans+=(-1)*dis[i][j]; printf("%lld\n",ans); return 0; }
G題
題意:給你n個隊伍,m個過題記錄。m行是某個隊伍過了題然後的罰時。輸出m行每次有人過題之後,1隊的排名
思想:樹狀陣列維護即可。樹狀陣列維護當前點過題的人數。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; struct node{ int x; int y; }no[maxn]; int team[maxn]; int score[maxn]; int sum[maxn]; pair<int,int>P[2*maxn]; int n,m,cnt; void add(int x,int valu) { while(x<=cnt) { sum[x]+=valu; x+=(x&(-x)); } } int ask(int x) { int ans=0; while(x>0) { ans+=sum[x]; x-=(x&(-x)); } return ans; } int main() { scanf("%d%d",&n,&m); P[cnt++]=make_pair(0,0); for(int i=0;i<m;i++) { scanf("%d%d",&no[i].x,&no[i].y); team[no[i].x]--; score[no[i].x]+=no[i].y; P[cnt++]=make_pair(team[no[i].x],score[no[i].x]); } sort(P,P+cnt); memset(team,0,sizeof(team)); memset(score,0,sizeof(score)); for(int i=0;i<m;i++) { int temp=lower_bound(P,P+cnt,make_pair(team[no[i].x],score[no[i].x]))-P+1; //減去上次影響 add(temp,-1); team[no[i].x]--; score[no[i].x]+=no[i].y; temp=lower_bound(P,P+cnt,make_pair(team[no[i].x],score[no[i].x]))-P+1;//加上現在的影響 add(temp,1); temp=lower_bound(P,P+cnt,make_pair(team[1],score[1]))-P+1;//計算隊伍1前邊有多少隊伍 printf("%d\n",ask(temp-1)+1);//計算當前點前邊的位置加上自己是最後一名 } return 0; }
I題
題意:求一個有向圖的最小環,輸出路徑。
思想:Floyd求最小環即可
J題
題意:給你n,m代表2遍的牙齒數量,問你牙齒總數或者是沒有牙齒。
思想:模擬即可 特判下0 0
K題
題意:給你b,n,e代表三類人,分別是慢的中速快的,然後給你每個人的速度,然後給你(b+n+e)/2個皮划艇的速度係數,一個皮划艇的速度=皮划艇的速度係數*(第一個的速度+第二個的速度)
思想:二分+貪心
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define scanf(a) scanf("%d",&a);
using namespace std;
const double eps = 1e-7;
const int maxn=1e5+5;
int a[maxn];
int b,n,e,m,sb,sn,se;
struct node{
int x;
int y;
int z;
int value;
bool operator < (const node &a)const {
return value < a.value;
}
}no[maxn];
int check(int mid)
{
int bb=b,nn=n,ee=e;
rep(i,1,m)
{
int cnt=0;
double temp = (double)(mid) / (double)a[i];
if(bb>=2)
no[cnt++]={2,0,0,sb+sb};
if(nn>=2)
no[cnt++]={0,2,0,sn+sn};
if(ee>=2)
no[cnt++]={0,0,2,se+se};
if(bb && nn)
no[cnt++]={1,1,0,sb+sn};
if(bb && ee)
no[cnt++]={1,0,1,sb+se};
if(nn && ee)
no[cnt++]={0,1,1,sn+se};
sort(no,no+cnt);
int flag=0;
rep(j,0,cnt-1)
{
if(temp - (double)(no[j].value) <= eps)
{
flag=1;
bb=bb-no[j].x;
nn=nn-no[j].y;
ee=ee-no[j].z;
break;
}
}
if(flag==0)
return 0;
}
return 1;
}
int main()
{
scanf(b);
scanf(n);
scanf(e);
m = (b+n+e)/2;
scanf(sb);
scanf(sn);
scanf(se);
rep(i,1,m)
scanf(a[i]);
int l=1;
int r=1e9;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
l=mid+1;
else
r=mid-1;
}
printf("%d\n",r);
return 0;
}
用ll也是OK的