题目:
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的暴力枚举第一个时间..然后推过去判断..值得注意的是一个钟的数位好坏在不同时间上是一样的..所以要更新那些数位确定有问题..哪些数位确定是好的..哪些数位是还未知的..
Program:
#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;
}
}
D - Idol
题意:
现在进行偶像选秀节目..有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;
}