2016-2017 ACM-ICPC Northeastern European Regional Contest (NEERC 16)
A:模拟
注意各种情况和细节~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<string> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 using namespace std; 8 9 char s[200]; 10 char now[200]; 11 12 int check(int pos){ 13 int flag=-1; 14 while(s[pos]>='a' && s[pos]<='z' || s[pos]>='A' && s[pos]<='Z'){ 15 flag=0; 16 if(s[pos]>='a' && s[pos]<='z') pos++; 17 else return -1; 18 } 19 if(flag<0) return flag; 20 return pos; 21 } 22 23 int main(){ 24 freopen("abbreviation.in","r",stdin); 25 freopen("abbreviation.out","w",stdout); 26 int n=0; 27 while(gets(s)){ 28 int len=strlen(s),flag=1,pos=0; 29 for(int i=0;i<len;i++){ 30 if(flag==1 && s[i]>='A' && s[i]<='Z'){ 31 now[++pos]=s[i]; 32 int f=check(i+1); 33 if(f==-1) printf("%c",s[i]),flag=2; 34 else{ 35 int tmp=1; 36 while(tmp!=-1 && s[f]==' ' && s[f+1]>='A' && s[f+1]<='Z'){ 37 tmp=check(f+2); 38 if(tmp!=-1) now[++pos]=s[f+1],f=tmp; 39 } 40 if(pos>=2){ 41 for(int j=1;j<=pos;j++) printf("%c",now[j]); 42 pos=0; 43 printf(" ("); 44 for(int j=i;j<=f-1;j++) printf("%c",s[j]); 45 printf(")"); 46 i=f; if(i!=len) printf("%c",s[i]); 47 } 48 else printf("%c",s[i]); 49 flag=1; 50 } 51 pos=0; 52 } 53 else if(!(s[i]>='A' && s[i]<='Z' || s[i]>='a' && s[i]<='z')) printf("%c",s[i]),flag=1; 54 else printf("%c",s[i]),flag=2; 55 } 56 puts(""); 57 } 58 return 0; 59 }
B:字典树+2-sat
用字典树求出字符串之间的关系辅助构图,之后用2-sat即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 include<bits/stdc++.h> 2 3 #define maxn 500000+5 4 #define maxm 4000000+5 5 6 using namespace std; 7 8 vector<char>c[maxn]; 9 vector<int>a[maxn<<1],g[maxm]; 10 int num,nx[maxn<<1][2],w[maxn<<1],w2[maxn<<1],pos[maxn],pr[maxn<<1],sf[maxn<<1]; 11 int n,m,p,l,root=1; 12 char s[maxn]; 13 14 inline void Insert(int& x,int y,int z){ 15 if(!x) x=++num; 16 if(y==l){ 17 a[x].push_back(z); 18 return; 19 } 20 Insert(nx[x][s[y]-'0'],y+1,z); 21 } 22 23 inline void Build(int x,int y,int z){ 24 if(!x) return; 25 int X=++num,Y=++num; 26 if(a[x].size()==0){ 27 pr[x]=X;sf[x]=Y; 28 } 29 else{ 30 pr[x]=++num;sf[x]=++num; 31 for(int i=0;i<a[x].size();i++){ 32 w[a[x][i]]=++num; 33 g[num].push_back(a[x][i]^1); 34 if(!i) g[pr[x]].push_back(num); 35 else g[w[a[x][i-1]]].push_back(num); 36 if(i==(int)a[x].size()-1) g[num].push_back(X); 37 w2[a[x][i]]=++num; g[num].push_back(a[x][i]^1); 38 } 39 for(int i=0;i<a[x].size();i++){ 40 if(i==(int)a[x].size()-1) g[Y].push_back(w2[a[x][i]]),g[a[x][i]].push_back(X); 41 else g[a[x][i]].push_back(w[a[x][i+1]]),g[w2[a[x][i+1]]].push_back(w2[a[x][i]]); 42 if(!i) g[w2[a[x][i]]].push_back(sf[x]),g[a[x][i]].push_back(sf[x]);else g[a[x][i]].push_back(w2[a[x][i-1]]); 43 } 44 } 45 if(y) g[y].push_back(pr[x]),g[sf[x]].push_back(z); 46 Build(nx[x][0],X,Y); Build(nx[x][1],X,Y); 47 } 48 49 bool b[maxm]; 50 int cnt; 51 int f[maxm],dfn[maxm],low[maxm],T,st[maxm],top; 52 53 inline void Dfs(int x){ 54 dfn[x]=low[x]=++T;st[++top]=x; 55 for(int i=0;i<g[x].size();i++){ 56 int v=g[x][i]; 57 if(!dfn[v]) Dfs(v),low[x]=min(low[x],low[v]);else 58 if(!f[v]) low[x]=min(low[x],dfn[v]); 59 } 60 if(low[x]==dfn[x]){ 61 ++cnt; 62 while(st[top]!=x) f[st[top--]]=cnt; 63 f[st[top--]]=cnt; 64 } 65 } 66 67 bool Tarjan(){ 68 for(int i=2;i<=num;i++) 69 if(!dfn[i])Dfs(i); 70 for(int i=1;i<=n;i++) 71 if(f[i<<1]==f[i<<1|1]) return 0; 72 return 1; 73 } 74 75 int main(){ 76 freopen("binary.in","r",stdin); 77 freopen("binary.out","w",stdout); 78 scanf("%d",&n); 79 memset(pos,-1,sizeof(pos));num=n<<1|1; 80 for(int i=1;i<=n;i++){ 81 scanf("%s",s);l=strlen(s); 82 for(int j=0;j<l;j++){ 83 if(s[j]=='?')pos[i]=j; 84 c[i].push_back(s[j]); 85 } 86 if(pos[i]==-1)Insert(root,0,i<<1|1),g[i<<1].push_back(i<<1|1);else{ 87 s[pos[i]]='0';Insert(root,0,i<<1|1); 88 s[pos[i]]='1';Insert(root,0,i<<1); 89 } 90 } 91 Build(1,0,0); 92 if(!Tarjan()) puts("NO"); 93 else{ 94 puts("YES"); 95 for(int i=1;i<=n;i++){ 96 for(int j=0;j<c[i].size();j++) 97 if(c[i][j]=='?')putchar((f[i<<1]<f[i<<1|1])+'0');else putchar(c[i][j]); 98 putchar('\n'); 99 } 100 } 101 return 0; 102 }
D:上下界费用流
将每个点和每个长度D的区间看作边,限制条件看作流量上下界,差分建图,无源汇最大费用费用流,非常巧妙的使用了差分建图。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #define N 100003 #define inf 2000000000 #define LL long long using namespace std; const LL INF=1e17; int tot,nxt[N],point[N],v[N],remain[N],can[N],last[N],n,k,t1,t2,a[N],b[N]; LL cost[N],dis[N],ans; void add(int x,int y,int z,LL k) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; cost[tot]=k; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; cost[tot]=-k; } int addflow(int s,int t) { int ans=inf; int now=t; while (now!=s) { ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s) { remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } bool spfa(int s,int t) { for (int i=1;i<=t;i++) dis[i]=INF,can[i]=0;; dis[s]=0; can[s]=1; queue<int> p; p.push(s); while (!p.empty()) { int now=p.front(); p.pop(); can[now]=0; for (int i=point[now];i!=-1;i=nxt[i]) if (remain[i]&&dis[v[i]]>dis[now]+cost[i]){ dis[v[i]]=dis[now]+cost[i]; last[v[i]]=i; if (!can[v[i]]) { can[v[i]]=1; p.push(v[i]); } } } if (dis[t]==INF) return false; int flow=addflow(s,t); ans+=dis[t]; return true; } int main() { freopen("delight.in","r",stdin); freopen("delight.out","w",stdout); scanf("%d%d%d%d",&n,&k,&t1,&t2); LL sum=0; tot=-1; memset(point,-1,sizeof(point)); for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=(LL)a[i]; for (int i=1;i<=n;i++) scanf("%d",&b[i]); int mn=t2; int mx=k-t1; int S=n+1; int SS=S+1; int TT=SS+1; for (int i=1;i<=n;i++) add(i,i+k>n?TT:i+k,1,-(b[i]-a[i])); for (int i=1;i<=n;i++) add(i,i+1>n?TT:i+1,mx-mn,0); for (int i=1;i<=k;i++) add(S,i,inf,0); add(SS,S,mx,0); while (spfa(SS,TT)); printf("%lld\n",sum-ans); for (int i=1;i<=2*n-1;i+=2) if (remain[i]) printf("E"); else printf("S"); printf("\n"); }
E:贪心+排序+二分计算贡献
考虑到每一个i时刻要用的单车如果有等待时间那到i+1的这段时间都有贡献,故画出取车还车的折线图,在y=b这条线下的面积就是所求。
可以把每一个时间段取出来排序并求前缀和,然后二分来回答每一个询问。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 6 #define maxn 100000+5 7 #define maxq 100000+5 8 9 using namespace std; 10 11 struct Query{ 12 int pos,t; 13 }c[maxq]; 14 15 struct Event{ 16 int opt,t,k; 17 }a[maxn]; 18 19 struct Data{ 20 int len,val; 21 bool operator <(const Data &T)const{ 22 return val<T.val; 23 } 24 }b[maxn]; 25 26 long long s[maxn],ss[maxn]; 27 int n,q; 28 29 bool cmp1(const Query & a,const Query &b){ 30 return a.pos<b.pos; 31 } 32 33 bool cmp2(const Query & a,const Query &b){ 34 return a.t<b.t; 35 } 36 37 int main(){ 38 freopen("expect.in","r",stdin); 39 freopen("expect.out","w",stdout); 40 scanf("%d%d",&n,&q); 41 for(int i=1;i<=n;i++){ 42 char op; getchar(); 43 scanf("%c%d%d",&op,&a[i].t,&a[i].k); 44 if(op=='-') a[i].opt=1; 45 else a[i].opt=2; 46 } 47 a[n+1].t=0x3f3f3f3f; 48 int now=0; 49 for(int i=1;i<=n;i++){ 50 if(a[i].opt==1) now-=a[i].k; 51 else now+=a[i].k; 52 b[i].len=a[i+1].t-a[i].t; 53 b[i].val=now; 54 } 55 sort(b+1,b+1+n); 56 for(int i=1;i<=n;i++){ 57 s[i]=s[i-1]+b[i].len; 58 ss[i]=ss[i-1]+(long long)b[i].len*b[i].val; 59 } 60 for(int i=1;i<=q;i++){ 61 scanf("%d",&c[i].t); 62 if(c[i].t+now<0){ 63 puts("INFINITY"); 64 continue; 65 } 66 int l=1,r=n-1,ans=0; 67 while(l<=r){ 68 int mid=(l+r)>>1; 69 if(-b[mid].val>c[i].t) ans=mid,l=mid+1; 70 else r=mid-1; 71 } 72 printf("%lld\n",-ss[ans]-s[ans]*c[i].t); 73 } 74 return 0; 75 }
F:概率DP
设dp[i]表示从i这里切一次,i以及i之后w的期望,很容易看出这是可以DP转移的
若i处是w,dp[i]=1/n*∑(∑(sum_c[i..j])+dp[j])否则是:dp[i]=1/n*∑(∑(sum_w[i..j])+dp[j]),维护一下sum_c和sum_w即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; double sum[1000010],dp[1000010]; char str[1000010]; int n; int main() { freopen("foreign.in","r",stdin); freopen("foreign.out","w",stdout); int i; scanf("%s",str); n=strlen(str); for(i=0;i<n;i++) { if(str[i]=='C') sum[i]=1.0; } for(i=n-1;i>=0;i--) sum[i]+=sum[i+1]; double sum_c=0.0,sum_w=0.0,cnt=0.0; if(str[n-1]=='C')sum_c=1.0; else sum_w=1.0; for(i=n-2;i>=0;i--) { if(str[i]=='C') { dp[i]=(cnt+sum_w)/(double)(n-i); sum_c+=(double)(n-i); } else { dp[i]=(cnt+sum_c)/(double)(n-i); sum_w+=(double)(n-i); } //cout<<dp[i]<<endl; cnt+=dp[i]; } printf("%.10lf\n",dp[0]); //cout<<dp[0]<<endl; return 0; }
J:物理题
用求重心的公式强行算即可,n^2的复杂度根本不虚
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> const double eps=1e-10; using namespace std; struct zx { double x,y; }; zx zx_all[5010],zx_a[5010]; int n,w,h,m; int vis[5010][5010]; int num[5010]; double le[5010],ri[5010]; int main() { freopen("jenga.in","ri",stdin); freopen("jenga.out","w",stdout); int i,j; scanf("%d%d%d%d",&n,&w,&h,&m); int l,k; num[h+1]=0; for(i=h;i>=1;i--) { le[i]=0; ri[i]=n*w; num[i]=num[i+1]+n; zx_all[i].x=zx_a[i].x=(double)(n*w)/2.0; zx_all[i].y=zx_a[i].y=(double)(n*w)/2.0; } int ans=-1; for(i=1;i<=m;i++) { scanf("%d%d",&l,&k); if(ans!=-1) continue; vis[l][k]=1; for(j=l;j>=1;j--) { num[j]--; if(num[j]==num[j+1]||num[h]==0) { ans=i; break; } } if(ans!=-1) continue; if(num[l]==num[l+1]) { ans=i; break; } else { for(j=1;j<=n;j++) { if(!vis[l][j]) { le[l]=(double)(j-1)*w; break; } } for(j=n;j>=1;j--) { if(!vis[l][j]) { ri[l]=(double)j*w; break; } } } double temp=0; double tmp=0; for(j=1;j<=n;j++) { if(!vis[l][j]) { temp+=((j-1)*w+w/2); tmp+=1.0; } } temp/=tmp; if(l%2==1) { zx_a[l].x=temp; } else { zx_a[l].y=temp; } for(j=l;j>=1;j--) { zx_all[j].x=(zx_all[j+1].x*num[j+1]+zx_a[j].x*(num[j]-num[j+1]))/num[j]; zx_all[j].y=(zx_all[j+1].y*num[j+1]+zx_a[j].y*(num[j]-num[j+1]))/num[j]; if(j!=h&&(j&1)&&((zx_all[j+1].x<=le[j]||zx_all[j+1].x>=ri[j])||(fabs(zx_all[j+1].x-le[j])<eps)||(fabs(zx_all[j+1].x-ri[j])<eps))) { ans=i; break; } else if(j!=h&&!(j&1)&&((zx_all[j+1].y<=le[j]||zx_all[j+1].y>=ri[j])||(fabs(zx_all[j+1].y-le[j])<eps)||(fabs(zx_all[j+1].y-ri[j])<eps))) { ans=i; break; } } } if(ans==-1) { puts("no"); } else { puts("yes"); printf("%d\n",ans); } return 0; }