2013 Asia Chengdu Regional Contest
hdu 4786 Fibonacci Tree http://acm.hdu.edu.cn/showproblem.php?pid=4786
copyright@ts 算法源于ts,用最小生成树可以求出最小权值,把所有边权取反可以求出最大权值,算法是如果有个斐波那契数在最小到最大值之间,就一定能构成。也就是如果大了就把1边换成0边,反之亦然。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mt(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 const int M=100010; 7 class Kruskal { ///最小生成树(无向图)o(ME*logME) 8 typedef int typec;///边权的类型 9 static const int ME=M;///边的个数 10 static const int MV=M;///点的个数 11 class UnionFindSet { ///并查集 12 int par[MV]; 13 public: 14 void init() { 15 mt(par,-1); 16 } 17 int getroot(int x) { 18 int i=x,j=x,temp; 19 while(par[i]>=0) i=par[i]; 20 while(j!=i) { 21 temp=par[j]; 22 par[j]=i; 23 j=temp; 24 } 25 return i; 26 } 27 bool unite(int x,int y) { 28 int p=getroot(x); 29 int q=getroot(y); 30 if(p==q)return false; 31 if(par[p]>par[q]) { 32 par[q]+=par[p]; 33 par[p]=q; 34 } else { 35 par[p]+=par[q]; 36 par[q]=p; 37 } 38 return true; 39 } 40 } f; 41 struct E { 42 int u,v; 43 typec w; 44 friend bool operator < (E a,E b) { 45 return a.w<b.w; 46 } 47 } e[ME]; 48 int le,num,n; 49 typec res; 50 public: 51 void init(int tn){///传入点的个数 52 n=tn; 53 le=res=0; 54 f.init(); 55 num=1; 56 } 57 void add(int u,int v,typec w) { 58 e[le].u=u; 59 e[le].v=v; 60 e[le].w=w; 61 le++; 62 } 63 typec solve(){///返回-1不连通 64 sort(e,e+le); 65 for(int i=0; i<le&&num<n; i++) { 66 if(f.unite(e[i].u,e[i].v)) { 67 num++; 68 res+=e[i].w; 69 } 70 } 71 if(num<n) res=-1; 72 return res; 73 } 74 }gx; 75 struct IN{ 76 int u,v,w; 77 }e[M]; 78 int F[32]; 79 void yes(){ 80 puts("Yes"); 81 } 82 void no(){ 83 puts("No"); 84 } 85 int main(){ 86 F[0]=F[1]=1; 87 for(int i=2;i<32;i++){ 88 F[i]=F[i-1]+F[i-2]; 89 } 90 int t,n,m; 91 while(~scanf("%d",&t)){ 92 for(int cas=1;cas<=t;cas++){ 93 scanf("%d%d",&n,&m); 94 gx.init(n); 95 for(int i=0;i<m;i++){ 96 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 97 gx.add(e[i].u,e[i].v,e[i].w); 98 } 99 int sma=gx.solve(); 100 printf("Case #%d: ",cas); 101 if(sma==-1){ 102 no(); 103 continue; 104 } 105 gx.init(n); 106 for(int i=0;i<m;i++){ 107 gx.add(e[i].u,e[i].v,-e[i].w); 108 } 109 int big=-gx.solve(); 110 bool flag=false; 111 for(int i=0;i<32;i++){ 112 if(sma<=F[i]&&F[i]<=big){ 113 flag=true; 114 break; 115 } 116 } 117 if(flag){ 118 yes(); 119 } 120 else{ 121 no(); 122 } 123 } 124 } 125 return 0; 126 }
Hard Disk Drive http://acm.hdu.edu.cn/showproblem.php?pid=4788
简单计算。1kb当成1000b,但是计算机当成1024b是1kb,所以输入1kb,实际上只有1000b/1024b个kb。
1 #include<cstdio> 2 char op[8]; 3 char cmp[16][16]={"B","KB","MB","GB","TB","PB","EB","ZB","YB"}; 4 int main(){ 5 int t,pre; 6 double now; 7 while(~scanf("%d",&t)){ 8 for(int cas=1;cas<=t;cas++){ 9 scanf("%d[%s",&pre,op); 10 now=pre; 11 int num=0; 12 for(int i=0;i<9;i++){ 13 if(cmp[i][0]==op[0]){ 14 num=i; 15 break; 16 } 17 } 18 for(int i=0;i<num;i++){ 19 now*=1000; 20 now/=1024; 21 } 22 printf("Case #%d: %.2f",cas,(pre-now)*100/pre); 23 puts("%"); 24 } 25 } 26 return 0; 27 }
Just Random http://acm.hdu.edu.cn/showproblem.php?pid=4790
题目要求 算 (x + y) mod p = m的概率,其中x属于a,b区间 y属于c,d区间。copyright@ts
考虑选择是随机等概率的。所以概率是出现上式的个数除以总的个数。总的个数好求,就是这个矩形区间长乘宽。
然后可以将矩形每一个点的值画出来,
1 2 3 4 5 这个是长度区间
0 1 2 3 4 5
1 2 3 4 5 6
2 3 4 5 6 7
这个是宽度区间
可以发现斜着的值是相等的。
矩阵中3,4,5的个数都是相等的,1,2构成的三角形分为第一区间,中间都相等的分为第二区间,后面的三角形分为第三区间。
因为是mod p 所以每p个会出现一个,所以第一第三区间中都是等差数列,求首项公差项数去求和,中间只要算出个数乘斜着的长度就是总的个数。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef __int64 LL; 5 LL gcd(LL a,LL b) { ///最大公约数 6 return b?gcd(b,a%b):a; 7 } 8 int main() { 9 int t; 10 LL a,b,c,d,p,m; 11 while(~scanf("%d",&t)) { 12 for(int cas=1; cas<=t; cas++) { 13 scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m); 14 if((b-a+1)>(d-c+1)) { 15 swap(a,c); 16 swap(b,d); 17 } 18 LL ans=0; 19 LL k=(a+c-m)/p;///第一个区间 20 if(a+c-m>=0&&(a+c-m)%p!=0) { 21 k++; 22 } 23 if(k*p+m<=b+c-1) { 24 LL first=k*p+m; 25 LL t=first-c; 26 LL a1=t-a+1; 27 LL num=(b+c-1-first)/p+1; 28 ans+=(a1+a1+p*(num-1))*num/2; 29 } 30 k = (b+c-m)/p;///第二个区间 31 if((b+c-m)>=0&&(b+c-m)%p!=0) { 32 k++; 33 } 34 if(k*p+m<=a+d) { 35 LL first=k*p+m; 36 LL num=(a+d-first)/p+1; 37 ans+=num*(b-a+1); 38 } 39 k=(a+d+1-m)/p;///第三个区间 40 if(a+d+1-m>=0&&(a+d+1-m)%p!=0) { 41 k++; 42 } 43 if(k*p+m<=b+d) { 44 LL first=k*p+m; 45 LL num=(b+d-first)/p+1; 46 LL t=first-d; 47 LL a1=b-t+1; 48 ans+=(a1+a1-p*(num-1))*num/2; 49 } 50 printf("Case #%d: ",cas); 51 if(!ans) { 52 puts("0/1"); 53 continue; 54 } 55 LL fenmu=(b-a+1)*(d-c+1); 56 LL d=gcd(ans,fenmu); 57 printf("%I64d/%I64d\n",ans/d,fenmu/d); 58 } 59 } 60 return 0; 61 }
Assignment For Princess http://acm.hdu.edu.cn/showproblem.php?pid=4781
构造一个图,n点m边,边权是1到m。保证没有重边没有自环。保证两两可达。任意一个回路的边权和要是3的倍数。
首先把n个点连成一个环。先满足两两可达的条件,1到2,。。。。n-1到n就直接用前一个的点的值来作为边权,n到1要算一下之前的和,然后选一个值保证总和是3的倍数。
构造成环以后,剩下的边只要考虑形成的环是3的倍数就行。
n^2的枚举两个点来连,能连的条件是他们之间没有边,并且构成的回路要是3的倍数。假设当前枚举到我们要加 i ---> j 如果和我们之前的大环小到大是同向的,那么就会和大环中的 j到i构成环。也就是说这个边 mod 3的余数 要和大环中i到j的余数相同。比如图中,如果想加入1到3,那么他会和原图的3->4->1构成环也就是他mod3要等于原来1到2到3的和mod3.
如果是反向的,那就要和大环中求和 mod 3 ==0 。可以预处理出大环1到 i的和,通过相减的关系就可以求出任意一段的和。
如图,如果要加3到1的,那就会和原来的1到2到3 形成环。也就是要和1到2到3的和相加是3的倍数。
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 const int M=1024; 5 struct G{ 6 struct E{ 7 int u,v,w; 8 }e[M]; 9 int le; 10 void init(){ 11 le=0; 12 } 13 void add(int u,int v,int w){ 14 e[le].u=u; 15 e[le].v=v; 16 e[le].w=w; 17 le++; 18 } 19 }g; 20 bool mat[M][M]; 21 int sum[M]; 22 bool vis[M]; 23 int main() { 24 int t,n,m; 25 while(~scanf("%d",&t)) { 26 for(int cas=1; cas<=t; cas++) { 27 scanf("%d%d",&n,&m); 28 printf("Case #%d:\n",cas); 29 g.init(); 30 sum[0]=0; 31 sum[1]=0; 32 mt(vis,0); 33 for(int i=1; i<n; i++) { 34 vis[i]=true; 35 g.add(i,i+1,i); 36 sum[i+1]=sum[i]+i; 37 } 38 for(int i=0; i<3; i++) { 39 if((n+i+sum[n])%3==0) { 40 vis[n+i]=true; 41 g.add(n,1,n+i); 42 break; 43 } 44 } 45 mt(mat,0); 46 for(int i=0; i<g.le; i++) { 47 int u=g.e[i].u; 48 int v=g.e[i].v; 49 mat[u][v]=true; 50 mat[v][u]=true; 51 } 52 bool ok=true; 53 for(int e=n; e<=m; e++) { 54 if(vis[e]) continue; 55 bool add=false; 56 for(int i=1; i<=n; i++) { 57 for(int j=1; j<=n; j++) { 58 if(i==j) continue; 59 if(mat[i][j]) continue; 60 if(i<j) { 61 int tmp=sum[j]-sum[i]; 62 if(e%3==tmp%3) { 63 g.add(i,j,e); 64 add=true; 65 mat[i][j]=true; 66 mat[j][i]=true; 67 break; 68 } 69 } else { 70 int tmp=sum[j]-sum[i]; 71 if((e+tmp)%3==0) { 72 g.add(i,j,e); 73 add=true; 74 mat[i][j]=true; 75 mat[j][i]=true; 76 break; 77 } 78 } 79 } 80 if(add) break; 81 } 82 if(!add) { 83 ok=false; 84 break; 85 } 86 } 87 if(ok) { 88 for(int i=0; i<g.le; i++) { 89 printf("%d %d %d\n",g.e[i].u,g.e[i].v,g.e[i].w); 90 } 91 } else { 92 puts("-1"); 93 } 94 } 95 } 96 return 0; 97 }
end