2017ICPC乌鲁木齐网络赛 全题解
来源:互联网 发布:阿里云中央仓库 编辑:程序博客网 时间:2024/04/30 02:46
A. Banana
直接暴力。
#include <bits/stdc++.h>using namespace std;typedef pair<int,int> PII;set<PII> ss;vector<int> le[55],ri[55];int main(){ int T,n,m,x,y; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); for (int i=1;i<=50;i++) { le[i].clear(); ri[i].clear(); } for (int i=1;i<=n;i++) { scanf("%d%d",&x,&y); le[y].push_back(x); } for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ri[x].push_back(y); } ss.clear(); for (int i=1;i<=50;i++) { for (int x:le[i]) { for (int y:ri[i]) { ss.insert(PII(x,y)); } } } for (auto &p:ss) { printf("%d %d\n",p.first,p.second); } puts(""); } return 0;}
B. Out-out-control cars
可以看作相对运动,然后三条射线跟三条线段判相交。
要注意的是大三角形的射线不碰到小三角形也可以yes,这个我们可以通过两个都判一遍来解决。
还有一种情况(数据里好像没有)是两者相对静止并且一个套一个,按照题意也是yes。
#include <bits/stdc++.h>using namespace std;const double eps=1e-8;struct Point { double x,y; Point() {} Point(double a,double b):x(a),y(b) {} Point operator +(const Point &R) { return Point(x+R.x,y+R.y); } Point operator -(const Point &R) { return Point(x-R.x,y-R.y); } Point operator *(const double &R) { return Point(x*R,y*R); } double operator ^(const Point &R) { return x*R.y-y*R.x; } void print() { printf("%.2f %.2f\n",x,y); }} t[2][4];struct Line { Point s,e; Line() {} Line(Point a,Point b):s(a),e(b) {}};int sgn(double x){ if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1;}int inner(int p,int q){ int res=0; double area=fabs((t[p][1]-t[p][0])^(t[p][2]-t[p][0])); for (int j=0;j<3;j++) { double arx=fabs((t[p][1]-t[q][j])^(t[p][2]-t[q][j])); arx+=fabs((t[p][0]-t[q][j])^(t[p][2]-t[q][j])); arx+=fabs((t[p][0]-t[q][j])^(t[p][1]-t[q][j])); if (sgn(arx-area)==0) ++res; } return res;}inline bool inter(Line l1,Line l2){ return max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) && max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) && max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) && max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) && sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 && sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0;}bool line_cross(){ for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { if (inter({t[0][i],t[0][(i+1)%3]},{t[1][j],t[1][(j+1)%3]})) return true; } } return false;}bool static_tri_cross(){ if (line_cross()) return true; return inner(0,1)||inner(1,0);}bool dynamic_tri_cross(int p,int q){ Point dlt(t[q][3]-t[p][3]); for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { Point P0(t[p][(i+1)%3]-t[p][i]); double rat=(P0^(t[q][j]-t[p][i]))/(dlt^P0); double mxx=max(t[p][(i+1)%3].x,t[p][i].x); double mnx=min(t[p][(i+1)%3].x,t[p][i].x); double mxy=max(t[p][(i+1)%3].y,t[p][i].y); double mny=min(t[p][(i+1)%3].y,t[p][i].y); if (rat>=0&&mnx<=t[q][j].x+rat*dlt.x&&t[q][j].x+rat*dlt.x<=mxx &&mny<=t[q][j].y+rat*dlt.y&&t[q][j].y+rat*dlt.y<=mxy) return true; } } return false;}int main(){ int T,cas=0; scanf("%d",&T); while (T--) { for (int i=0;i<2;i++) { for (int j=0;j<4;j++) { scanf("%lf%lf",&t[i][j].x,&t[i][j].y); } } printf("Case #%d: ",++cas); if (sgn(t[1][3].x-t[0][3].x)==0&&sgn(t[1][3].y-t[0][3].y)==0) { puts(static_tri_cross()?"YES":"NO"); } else { puts(dynamic_tri_cross(0,1)||dynamic_tri_cross(1,0)?"YES":"NO"); } } return 0;}
C. Coconut
直接模拟。
#include <bits/stdc++.h>using namespace std;int c[1005], d[1005];int main(){ int T; scanf("%d",&T); while(T--) { int n, b; scanf("%d %d", &n, &b); for(int i = 0; i < n; ++i) { scanf("%d", c + i); } for(int i = 1; i < n; ++i) { scanf("%d", d + i); } int cap = c[0]; int f = 1; for(int i = 1; i < n; ++i) { cap -= b * d[i]; if(cap < 0) { f = 0; break; } cap += c[i]; } if(f) puts("Yes"); else puts("No"); } return 0;}
D. Hack Portals
poj原题。没做过,所以比赛的时候也没做
按照坐标排序后,有一个贪心的结论:i到j这一段区间中,最优情况下最后一个做的不是i就是j。
考虑区间dp,我们用dp[i][j][0]表示i到j这一段最后做i的最小花费,dp[i][j][1]表示i到j这一段最后做j的最小花费。
转移还是挺容易的,转移了以后还要再考虑一下开放的时间。
#include <bits/stdc++.h>using namespace std;const int N=1010,INF=1<<29;int dp[N][N][2];struct Classroom { int x,t; bool operator <(const Classroom &R) const { return x<R.x; }} c[N];inline void updm(int &x,int y){ if (y<x) x=y;}int main(){ int T,cas=0; scanf("%d",&T); while (T--) { int n,m,b; scanf("%d%d%d",&n,&m,&b); for (int i=1;i<=n;i++) { scanf("%d%d",&c[i].x,&c[i].t); } sort(c+1,c+n+1); dp[1][n][0]=max(c[1].x,c[1].t); dp[1][n][1]=max(c[n].x,c[n].t); for (int l=n-1;l>=1;l--) { for (int i=1;i<=n;i++) { int j=i+l-1; if (j>n) break; dp[i][j][0]=dp[i][j][1]=INF; if (i>1) { updm(dp[i][j][0],dp[i-1][j][0]+c[i].x-c[i-1].x); updm(dp[i][j][1],dp[i-1][j][0]+c[j].x-c[i-1].x); } if (j<n) { updm(dp[i][j][0],dp[i][j+1][1]+c[j+1].x-c[i].x); updm(dp[i][j][1],dp[i][j+1][1]+c[j+1].x-c[j].x); } if (dp[i][j][0]<c[i].t) dp[i][j][0]=c[i].t; if (dp[i][j][1]<c[j].t) dp[i][j][1]=c[j].t; } } int ans=INF; for (int i=1;i<=n;i++) { updm(ans,min(dp[i][i][0],dp[i][i][1])+abs(b-c[i].x)); } printf("Case #%d: %d\n",++cas,ans); } return 0;}
E. Half-consecutive Numbers
打表。反正我们队只会打表了
#include <bits/stdc++.h>using namespace std;using ll = long long;ll li[] = {0, 1, 8, 49, 288, 1681, 9800, 57121, 332928, 1940449, 11309768, 65918161, 384199200, 2239277041L, 13051463048L, 76069501249L, 443365544448L, 2584123765441L, 15061377048200L, 87784138523761L, 511643454094368L, 2982076586042449L, 17380816062160328L};int main() { int T; scanf("%d", &T); for(int i = 0; i != T; ++i) { ll n; scanf("%lld", &n); int idx = 0; while(li[idx] < n) ++idx; printf("Case #%d: %lld\n", i + 1, li[idx]); } return 0;}
F. Islands
hdu原题。
缩点以后看出度为0的点数和入度为0的点数,答案为较大值。注意特判只有1个scc。
#include <bits/stdc++.h>using namespace std;const int MAXN = 10010;//点数const int MAXM = 100010;//边数struct Edge { int fr,to,next;} eg[MAXM];int head[MAXN],tot;int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~sccint Index,top;int scc;//强连通分量的个数bool Instack[MAXN];int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc//num数组不一定需要,结合实际情况void addedge(int u,int v){ eg[tot].fr = u; eg[tot].to = v; eg[tot].next = head[u]; head[u] = tot++;}void Tarjan(int u){ int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; i != -1; i = eg[i].next) { v = eg[i].to; if( !DFN[v] ) { Tarjan(v); if( Low[u] > Low[v] )Low[u] = Low[v]; } else if(Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v]; } if(Low[u] == DFN[u]) { scc++; do { v = Stack[--top]; Instack[v] = false; Belong[v] = scc; num[scc]++; } while( v != u); }}void solve(int N){ memset(DFN,0,sizeof(DFN)); memset(Instack,false,sizeof(Instack)); memset(num,0,sizeof(num)); Index = scc = top = 0; for(int i = 1; i <= N; i++) if(!DFN[i]) Tarjan(i);}void init(){ tot = 0; memset(head,-1,sizeof(head));}int in[MAXN],out[MAXN];int main(){ int T,n,m,x,y; scanf("%d",&T); while (T--) { init(); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); addedge(x,y); } solve(n); if (scc==1) { puts("0"); } else { for (int i=1;i<=scc;i++) { in[i]=out[i]=0; } for (int i=0;i<tot;i++) { int u=Belong[eg[i].fr]; int v=Belong[eg[i].to]; if (u!=v) { out[u]++; in[v]++; } } int t1=0,t2=0; for (int i=1;i<=scc;i++) { if (in[i]==0) t1++; if (out[i]==0) t2++; } printf("%d\n",max(t1,t2)); } } return 0;}
G. Query on a string
因为模式串的长度很短,小于等于10,所以修改一个字符最多只会影响主串中10个位置的匹配情况。那么操作可以转化为10次单点修改和区间求和,用一个树状数组维护就可以了。有影响的那个部分可以用kmp匹配一下。
#include <bits/stdc++.h>using namespace std;const int N=100010;int nxt[N],c[N];bool b[N];char s[N],t[N];int T,n,ls,lt;void ins(int x,int d){ for (int i=x+1;i<N;i+=i&(-i)) { c[i]+=d; }}int get(int x){ int res=0; for (int i=x+1;i;i-=i&(-i)) { res+=c[i]; } return res;}void kmp_pre(char x[],int m,int nxt[]){ int i,j; j=nxt[0]=-1; i=0; while(i<m) { while(-1!=j && x[i]!=x[j])j=nxt[j]; nxt[++i]=++j; }}void KMP_Count(char x[],int m,char y[],int from,int to){ for (int i=from;i<=to;i++) { if (b[i]) { b[i]=false; ins(i,-1); } } int i=from,j=0; while(i<to+lt) { while(-1!=j && y[i]!=x[j]) j=nxt[j]; i++; j++; if(j>=m) { b[i-m]=true; ins(i-m,1); j=nxt[j]; } }}int main(){ scanf("%d",&T); while (T--) { scanf("%d",&n); scanf("%s",s); scanf("%s",t); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); ls=strlen(s); lt=strlen(t); kmp_pre(t,lt,nxt); KMP_Count(t,lt,s,0,ls-lt); while (n--) { char op[2]; scanf("%s",op); if (op[0]=='Q') { int l,r; scanf("%d %d",&l,&r); l--;r--; if (r-l+1<lt) { puts("0"); } else { printf("%d\n",get(r-lt+1)-get(l-1)); } } else { int x;char ch; scanf("%d %c",&x,&ch); if (s[--x]!=ch) { s[x]=ch; KMP_Count(t,lt,s,max(0,x-lt+1),min(ls-lt,x)); } } } puts(""); } return 0;}
H. Skiing
队友一下子就读懂了,加个源跑最长路就行。
#include <bits/stdc++.h>using namespace std;const int N=10010;const int INF=1<<29;struct Edge { int go,next,val;} eg[120000];int last[N],tot;int dp[N];bool mark[N];int C,n,m;void addedge(int x,int y,int z){ eg[tot]={y,last[x],z}; last[x]=tot++;}bool spfa(int S){ for (int i = 1; i <= n; i++) dp[i] = -INF; memset(mark,0,sizeof(mark)); queue<int> que; que.push(S); dp[S] = 0; while (!que.empty()) { int u = que.front(); que.pop(); mark[u] = false; for (int i=last[u];i!=-1;i=eg[i].next) { int v=eg[i].go; if (dp[u]+eg[i].val>dp[v]) { dp[v]=dp[u]+eg[i].val; if (!mark[v]) { mark[v]=true; que.push(v); } } } } return false;}int main(){ scanf("%d",&C); while (C--) { int x,y,z; scanf("%d%d",&n,&m); tot=0; memset(last,-1,sizeof(last)); for (int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); } for (int i=1;i<=n;i++) { addedge(0,i,0); } spfa(0); int ans=-1; for (int i=1;i<=n;i++) { ans=max(ans,dp[i]); } printf("%d\n",ans); } return 0;}
I. Colored Graph
比赛的时候直接抄的论文。还抄错了好多次
回忆同色三角形的计数过程,其实是算了异色三角形的个数
现要使得同色三角形个数尽量小,那么就要使每个点的
由于和一定,两项自然是越接近结果越大。考虑把点集分为两个,每个集合内部的边都是白色,两个集合之间的都是黑色。
若
下面重点讨论
在
首先把黑边分散地改成白边,即把在
所以还能更优,当然这时不能再改
#include <bits/stdc++.h>using namespace std;int g[666][666];int main(){ int T; scanf("%d",&T); while (T--) { int V; scanf("%d",&V); int n=V/2,ans=0; for (int i=1;i<=n;i++) { for (int j=i+1;j<=n;j++) { g[i][j]=g[j][i]=1; } } for (int i=n+1;i<=V;i++) { for (int j=i+1;j<=V;j++) { g[i][j]=g[j][i]=1; } } for (int i=1;i<=n;i++) { for (int j=n+1;j<=V;j++) { g[i][j]=g[j][i]=2; } } if (V&1) { ans=n*(n-1)*(n-2)/6+(n+1)*n*(n-1)/6-n/2; if (n&1) { for (int i=1;i<=n-1;i++) { g[i][i+n]=g[i+n][i]=1; } for (int i=n+1;i<=n+n-2;i+=2) { g[i][i+1]=g[i+1][i]=2; } } else { for (int i=1;i<=n;i++) { g[i][i+n]=g[i+n][i]=1; } for (int i=n+1;i<=n+n-1;i+=2) { g[i][i+1]=g[i+1][i]=2; } } } else { ans=n*(n-1)*(n-2)/3; } printf("%d\n",ans); for (int i=1;i<=V;i++) { for (int j=1;j<=V;j++) { printf("%d%c",g[i][j]," \n"[j==V]); } } } return 0;}
J. Our Journey of Dalian Ends
hdu原题。
中转站为源做一遍最小费用流。
#include <bits/stdc++.h>using namespace std;const int MAXN = 20010;const int MAXM = 100000;const int INF = 0x3f3f3f3f;struct Edge { int to,next,cap,flow,cost;} eg[MAXM];int head[MAXN],tol;int pre[MAXN],dis[MAXN];bool vis[MAXN];int N;//节点总个数,节点编号从0~N-1void addedge(int u,int v,int cap,int cost){ eg[tol].to = v; eg[tol].cap = cap; eg[tol].cost = cost; eg[tol].flow = 0; eg[tol].next = head[u]; head[u] = tol++; eg[tol].to = u; eg[tol].cap = 0; eg[tol].cost = -cost; eg[tol].flow = 0; eg[tol].next = head[v]; head[v] = tol++;}bool spfa(int s,int t){ queue<int>q; for(int i = 0; i < N; i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = eg[i].next) { int v = eg[i].to; if(eg[i].cap > eg[i].flow && dis[v] > dis[u] + eg[i].cost ) { dis[v] = dis[u] + eg[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t] == -1)return false; else return true;}//返回的是最大流,cost存的是最小费用int minCostMaxflow(int s,int t,int &cost){ int flow = 0; cost = 0; while(spfa(s,t)) { int Min = INF; for(int i = pre[t]; i != -1; i = pre[eg[i^1].to]) { if(Min > eg[i].cap - eg[i].flow) Min = eg[i].cap - eg[i].flow; } for(int i = pre[t]; i != -1; i = pre[eg[i^1].to]) { eg[i].flow += Min; eg[i^1].flow -= Min; cost += eg[i].cost * Min; } flow += Min; } return flow;}char s[10010][1000],t[10010][1000];int c[10010];map<string,int> mp;int main(){ int C; scanf("%d",&C); while (C--) { int m,n=0; scanf("%d",&m); mp.clear(); tol = 0; memset(head,-1,sizeof(head)); for (int i=0;i<m;i++) { scanf("%s%s%d",s[i],t[i],&c[i]); if (mp.find(s[i])==mp.end()) { mp[s[i]]=n++; } if (mp.find(t[i])==mp.end()) { mp[t[i]]=n++; } } int S=mp["Shanghai"]; for (int i=0;i<m;i++) { int u=mp[s[i]],v=mp[t[i]]; addedge(u,n+v,1,c[i]); addedge(v,n+u,1,c[i]); } for (int i=0;i<n;i++) { addedge(n+i,i,1,0); } int T=n+n;N=T+1; addedge(n+mp["Dalian"],T,1,0); addedge(n+mp["Xian"],T,1,0); int ans=0; if (minCostMaxflow(S,T,ans)<2) { puts("-1"); continue; } printf("%d\n",ans); } return 0;}
- 2017ICPC乌鲁木齐网络赛 全题解
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 题解
- 2017 ACM-ICPC 亚洲区乌鲁木齐赛网络赛 E
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017ICPC乌鲁木齐网络赛E Half-consecutive Numbers
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛
- 2017乌鲁木齐网络赛
- 2017 ACM-ICPC 亚洲区乌鲁木齐赛网络赛 E. Half-consecutive Numbers
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛-A. Banana
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛C. Coconut
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 H (简单DP)
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 A. Banana(连通性水题)
- Eclipse中step-into/step-over/step-out什么区别
- Selenium遇到的问题8 python利用xlwt模块操作xls数据显示IO错误(Python中正反斜杠的用法)
- linux下的掩码umask
- Hadoop之--flume安装配置
- decode-ways
- 2017ICPC乌鲁木齐网络赛 全题解
- 初始化一个mvn工程
- Node.js模块系统
- Qt音乐播放器的实现(未完持续)
- SpringMVC + MyBatis + Mysql + Redis(作为二级缓存) 配置
- 不同浏览器对post上传文件时,文件名的处理方式不同。
- leetcode 230. Kth Smallest Element in a BST 二叉搜索树BST的中序遍历
- linux XShell上传、下载本地文件到linux服务器
- 设置背景透明文字内容不透明方法