题目:
Click here
A - Admiral
题意:
有V(2<=V<=1000个点编号为1~V..有E(3<=E<=10000)条有向边...现在两个人同时从1点出发..要到达V点..除了起点和终点..中间不能走相同的边..相同的点..问两人路径总和最少是多少...
题解:
陈题...拆点..起点和终点做边容量为2..费用为0(因为起点和终点会经过两次)...其他点间做容量为1..费用为0的有向边...然后点之间的边容量为1..费用为其长度..然后跑从1到 V点跑一次最小费用最大流..得到的最小费用就是答案..
Program:
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> #include<queue> #define MAXN 2205 #define MAXM 50005 #define oo 10000007 #define ll long long using namespace std; struct MCMF { struct node { int x,y,c,v,next; }line[MAXM]; int Lnum,_next[MAXN],pre[MAXN],dis[MAXN],flow,cost; bool inqueue[MAXN]; void initial(int n) { Lnum=-1; for (int i=0;i<=n;i++) _next[i]=-1; } void addline(int x,int y,int c,int v) { line[++Lnum].next=_next[x],_next[x]=Lnum; line[Lnum].x=x,line[Lnum].y=y,line[Lnum].c=c,line[Lnum].v=v; line[++Lnum].next=_next[y],_next[y]=Lnum; line[Lnum].x=y,line[Lnum].y=x,line[Lnum].c=0,line[Lnum].v=-v; } bool SPFA(int s,int e) { int x,k,y; queue<int> Q; while (!Q.empty()) Q.pop(); memset(dis,0x7f,sizeof(dis)); memset(inqueue,false,sizeof(inqueue)); Q.push(s); dis[s]=0,pre[s]=-1; while (!Q.empty()) { x=Q.front(),Q.pop(),inqueue[x]=false; for (k=_next[x];k!=-1;k=line[k].next) if (line[k].c) { y=line[k].y; if (dis[y]>dis[x]+line[k].v) { dis[y]=dis[x]+line[k].v; pre[y]=k; if (!inqueue[y]) { inqueue[y]=true; Q.push(y); } } } } if (dis[e]>oo) return false; flow=oo,cost=0; for (k=pre[e];k!=-1;k=pre[line[k].x]) flow=min(flow,line[k].c),cost+=line[k].v; cost*=flow; for (k=pre[e];k!=-1;k=pre[line[k].x]) line[k].c-=flow,line[k^1].c+=flow; return true; } void MinCostMaxFlow(int s,int e,int &Aflow,int &Acost) { Aflow=0,Acost=0; while (SPFA(s,e)) { Aflow+=flow; Acost+=cost; } } }T; int main() { int V,E,s,e,Af,Ac,u,v,c,i; while (~scanf("%d%d",&V,&E)) { s=1<<1,e=V<<1|1,T.initial(e+10); for (i=2;i<V;i++) T.addline(i<<1,i<<1|1,1,0); T.addline(1<<1,1<<1|1,2,0),T.addline(V<<1,V<<1|1,2,0); while (E--) { scanf("%d%d%d",&u,&v,&c); T.addline(u<<1|1,v<<1,1,c); } T.MinCostMaxFlow(s,e,Af,Ac); printf("%d\n",Ac); } return 0; } /* 5 6 1 5 100 1 2 1 1 3 1 2 4 1 3 4 1 4 5 1 6 11 1 2 23 1 3 12 1 4 99 2 5 17 2 6 73 3 5 3 3 6 21 4 6 8 5 2 33 5 4 5 6 5 20 */
D - Digital Clock
题意:
现在一个每个数字7数码的数码钟可能显示有问题了...有问题是指可能有些位置不亮了..现在给出 N(1<=N<=50)个分钟连续递增的世界..可能存在显示错误..能推断出第一个时间可能是那些吗?...
题解:
阅读理解题...打出每个数字的7个数码位的01情况..然后24*60的暴力枚举第一个时间..然后推过去判断..值得注意的是一个钟的数位好坏在不同时间上是一样的..所以要更新那些数位确定有问题..哪些数位确定是好的..哪些数位是还未知的..
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <limits> #include <cstdlib> using namespace std; struct node { int h0,h1,m0,m1; }P[55]; /*bool C[10][10]={{1,1,0,0,0,0,0,1,0,0}, {0,1,0,0,0,0,0,0,0,0}, {0,0,1,0,0,0,0,0,0,0}, {0,1,0,1,0,0,0,1,0,0}, {0,1,0,0,1,0,0,0,0,0}, {0,0,0,0,0,1,0,0,0,0}, {0,0,0,0,0,1,1,0,0,0}, {0,1,0,0,0,0,0,1,0,0}, {1,1,1,1,1,1,1,1,1,1}, {0,1,0,1,1,1,0,1,0,1} }; */ bool C[10][7]={{1,1,1,0,1,1,1}, {0,0,1,0,0,1,0}, {1,0,1,1,1,0,1}, {1,0,1,1,0,1,1}, {0,1,1,1,0,1,0}, {1,1,0,1,0,1,1}, {1,1,0,1,1,1,1}, {1,0,1,0,0,1,0}, {1,1,1,1,1,1,1}, {1,1,1,1,0,1,1} }; int H[4][7]; bool ok(int p,int x0,int x) { for (int i=0;i<7;i++) { if (!C[x0][i] && C[x][i]) return false; if (H[p][i]==0 && C[x][i]) return false; if (H[p][i]==1 && C[x0][i] && !C[x][i]) return false; if (C[x0][i] && C[x][i]) H[p][i]=1; if (C[x0][i] && !C[x][i]) H[p][i]=0; } return true; } bool judge(int n,int h,int m) { int t,h0,h1,m0,m1; for (t=0;t<4;t++) for (h0=0;h0<7;h0++) H[t][h0]=-1; // h=23,m=25;// for (t=1;t<=n;t++) { h0=h/10,h1=h%10; m0=m/10,m1=m%10; if (!ok(0,h0,P[t].h0)) return false; if (!ok(1,h1,P[t].h1)) return false; if (!ok(2,m0,P[t].m0)) return false; if (!ok(3,m1,P[t].m1)) return false; m++; if (m==60) m=0,h++; if (h==24) h=m=0; } return true; } int main() { int n,i,h,m; bool f; char c; // freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while (~scanf("%d",&n)) { for (i=1;i<=n;i++) { scanf("%d",&h); do { c=getchar(); } while (c!=':'); scanf("%d",&m); P[i].h0=h/10,P[i].h1=h%10; P[i].m0=m/10,P[i].m1=m%10; } f=false; for (h=0;h<24;h++) for (m=0;m<60;m++) if (judge(n,h,m)) { if (f) printf(" "); printf("%d%d:%d%d",h/10,h%10,m/10,m%10); f=true; } if (!f) printf("none"); printf("\n"); } return 0; }
E - Edge Case
题意:
没读这题.....
题解:
从3开始的Fibonacci数列...但是结果会很大.. 要用大数
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <limits> #include <cstdlib> using namespace std; const int MAXD = 10000, DIG = 9, BASE = 1000000000; const unsigned long long BOUND = numeric_limits <unsigned long long> :: max () - (unsigned long long) BASE * BASE; class bignum { private: int digits[MAXD]; int D; public: friend ostream &operator<<(ostream &out,bignum &c); inline void trim() { while(D > 1 && digits[D-1] == 0 ) D--; } inline void dealint(long long x) { memset(digits,0,sizeof(digits)); D = 0; do { digits[D++] = x % BASE; x /= BASE; } while(x > 0); } inline void dealstr(char *s) { memset(digits,0,sizeof(digits)); int len = strlen(s),first = (len + DIG -1)%DIG + 1; D = (len+DIG-1)/DIG; for(int i = 0; i < first; i++) digits[D-1] = digits[D-1]*10 + s[i] - '0'; for(int i = first, d = D-2; i < len; i+=DIG,d--) for(int j = i; j < i+DIG; j++) digits[d] = digits[d]*10 + s[j]-'0'; trim(); } inline char *print() { trim(); char *cdigits = new char[DIG * D + 1]; int pos = 0,d = digits[D-1]; do { cdigits[pos++] = d % 10 + '0'; d/=10; } while(d > 0); reverse(cdigits,cdigits+pos); for(int i = D - 2; i >= 0; i--,pos += DIG) for(int j = DIG-1,t = digits[i]; j >= 0; j--) { cdigits[pos+j] = t%10 + '0'; t /= 10; } cdigits[pos] = '\0'; return cdigits; } bignum() { dealint(0); } bignum(long long x) { dealint(x); } bignum(int x) { dealint(x); } bignum(char *s) { dealstr(s); } inline bignum operator + (const bignum &o) const { bignum sum = o; int carry = 0; for (sum.D = 0; sum.D < D || carry > 0; sum.D++) { sum.digits [sum.D] += (sum.D < D ? digits [sum.D] : 0) + carry; if (sum.digits [sum.D] >= BASE) { sum.digits [sum.D] -= BASE; carry = 1; } else carry = 0; } sum.D = max (sum.D, o.D); sum.trim (); return sum; } }; ostream &operator<<(ostream &out, bignum &c) { out<<c.print(); return out; } int main() { int p; bignum a,b,c; while (cin>>p) { if (p==3) { printf("4\n"); continue; } p-=4,a=4,b=7; while (p--) { c=a+b; a=b,b=c; } cout<<b<<endl; } }
题意:
现在进行偶像选秀节目..有N(1<=N<=1000)个选手..编号为1~N...有M(1<=M<=10000)个评委..每个评委会投出两票..若一个票x为正数则说明该评委希望x晋级..若一个票为负数..则说明该评委希望-x被淘汰..现在1号选手黑入了系统..看到了每个评委的票..于是决定安排一个晋级方案..包括自己..同时让所有的评委两票中至少有一个满足条件..请问是否存在晋级方案...
题解:
阅读理解...读懂题后就发现是简单的2-sat..因为对于一个评委...如果一个人不满足了..另一个必须满足..可以构造关系..然后从1号晋级的点出发dfs染色..判断若其染色的点有一个人淘汰而又晋级的就说明无解..输出no...否则输出yes...
Program:
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> #include<stack> #include<queue> #define MAXN 2205 #define MAXM 25005 #define oo 1000000007 #define ll long long using namespace std; struct node { int u,v,next; }edge[MAXM]; int ne,_next[MAXN],DfsIndex,tpnum,tp[MAXN],dfn[MAXN],low[MAXN]; void addedge(int u,int v) { edge[++ne].next=_next[u],_next[u]=ne; edge[ne].u=u,edge[ne].v=v; } bool instack[MAXN]; stack<int> S; void tarjan(int x) { dfn[x]=low[x]=++DfsIndex; instack[x]=true,S.push(x); for (int k=_next[x];k;k=edge[k].next) { int v=edge[k].v; if (!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); }else if (instack[v]) low[x]=min(low[x],dfn[v]); } if (dfn[x]==low[x]) { tpnum++; do { x=S.top(),S.pop(); instack[x]=false; tp[x]=tpnum; }while (low[x]!=dfn[x]); } } bool color[MAXN]; bool judge(int n) { for (int i=1;i<=n;i++) { if (tp[i<<1]==tp[i<<1|1]) return false; if (color[i<<1] && color[i<<1|1]) return false; } return true; } void dfs(int x) { color[x]=1; for (int k=_next[x];k;k=edge[k].next) if (!color[edge[k].v]) dfs(edge[k].v); } int main() { int n,m,u,v,i; while (~scanf("%d%d",&n,&m)) { ne=0,memset(_next,0,sizeof(_next)); while (m--) { scanf("%d%d",&u,&v); if (u<0) u=(-u)<<1; else u=u<<1|1; if (v<0) v=(-v)<<1; else v=v<<1|1; addedge(u^1,v),addedge(v^1,u); } memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); while (!S.empty()) S.pop(); tpnum=DfsIndex=0; for (i=2;i<=(n<<1|1);i++) if (!dfn[i]) tarjan(i); memset(color,false,sizeof(color)); dfs(3); if (!judge(n)) printf("no\n"); else printf("yes\n"); } return 0; }
J - Joint Venture
题意:
现在给出一个数(1是特殊的..代表10000000)..又给出N(2<=N<=500000)个数...问能否从这N个数中选择两个数A,B相加等于给的第一个数..若能..请输出[A-B]最大的..
题解:
先排序..然后扫描上界..二分出下届..更新答案..
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; int x,a[1000010]; int n; int main() { while(scanf("%d",&x)!=EOF){ x*=(int)1e7; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); bool found=false; for(int i=1;i<=n;i++) { int tt=x-a[i]; int High=n,Low=i+1,mid; while(Low<High){ mid=Low+(High-Low)/2; if(a[mid]>=tt) High=mid; else Low=mid+1; } if(a[Low]==tt && Low<=n ) { printf("yes %d %d\n",a[i],a[Low]); found=true; break; } if(a[i]>x) break; } if(!found) printf("danger\n" ); } return 0; }