H - Hard Disk Drive
纯水题,直接贴代码;
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
int main()
{
int T;
char str[10];
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
int m;
scanf("%d[",&m);
// strcpy(str,"\0");
scanf("%s",&str);
double x=1000.0/1024;
if(strcmp(str,"B]")==0)
{
printf("Case #%d: 0.00%%\n",i);
}
if(strcmp(str,"KB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x)*100);
}
if(strcmp(str,"MB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x)*100);
}
if(strcmp(str,"GB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x)*100);
}
if(strcmp(str,"TB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x*x)*100);
}
if(strcmp(str,"PB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x*x*x)*100);
}
if(strcmp(str,"EB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x*x*x*x)*100);
}
if(strcmp(str,"ZB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x*x*x*x*x)*100);
}
if(strcmp(str,"YB]")==0)
{
printf("Case #%d: %.2f%%\n",i,(1-x*x*x*x*x*x*x*x)*100);
}
}
return 0;
}
J - Just Random
这道题刚开始老是T,但是就是当时就是想不到好的办法。今天在网上看到了比较好的思路。/*
这题就是要找在[a,b] [c,d] 之间,和模p等于m的对数。
把[a,b] [c,d]所有可能组合的和写成下列形式。
a+c a+c+1 a+c+2 .................. a+d
a+c+1 a+c+2 a+c+3 ........ a+d a+d+1
a+c+2 a+c+3 a+d a+d+1 a+d+2
....................
...................
b+c b+c+1 ...............................................b+d;
上面大致形成一个斜的矩阵。
使用b+c 和 a+d两条竖线,就可以分成三部分。前后两部分个数是等差数列,中间个数是相等的。
只需要讨论下b+c 和 a+d的大小。 然后找到%p==m 的位置,求和就可以搞定了。
*/
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
__int64 gcd(__int64 a,__int64 b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int main()
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
__int64 a,b,c,d,p,q;
scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&q);
__int64 ans=0;
if(b-a>d-c) swap(b,d),swap(a,c);
__int64 he,en,m,n,u,v,s,t;
//前半部分
m=(a+c)%p;
he=(q+p-m)%p;
n=(he+a+c-q)/p;
u=(b+c-1)%p;
en=(u-q+p)%p;
v=(b+c-1-en-q)/p;
ans+=(v-n+1)*(he+1)+(v-n)*(v-n+1)/2*p;
//中间
m=(b+c)%p;
he=(p+q-m)%p;
n=(b+c+he-q)/p;
u=(a+d)%p;
en=(u+p-q)%p;
v=(a+d-en-q)/p;
ans+=(v-n+1)*(b-a+1);
//后半部分
m=(a+d+1)%p;
he=(p+q-m)%p;
n=(a+d+1+he-q)/p;
u=(b+d)%p;
en=(u+p-q)%p;
v=(b+d-en-q)/p;
ans+=(v-n+1)*(en+1)+(v-n+1)*(v-n)/2*p;
__int64 sum=(b-a+1)*(d-c+1);
__int64 gc=gcd(sum,ans);
printf("Case #%d: %I64d/%I64d\n",i,ans/gc,sum/gc);
}
return 0;
}
比赛的时候队友做出了这道题,我当时没理解。然后在网上看了许多解题报告,
题意是问能否由白色边构成一个生成树,然后生成树的白边数是一个斐波那契数列。思路,通过并查集来判断生成树的情况,然后只要在最大的白边数和最小的白边数间存在斐波那契数就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#define maxn 100005
using namespace std;
int fa[maxn],fo[maxn];
int m,n;
struct
{
int a,b,c;
}edge[maxn];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int solve(int p)
{
int sum=0;
for(int j=1;j<=maxn;j++) fa[j]=j;
for(int j=1;j<=n;j++)
if(edge[j].c!=p)
{
int u=find(edge[j].a);
int v=find(edge[j].b);
if(u!=v)
{
fa[u]=v;
sum++;
}
}
return sum;
}
int main()
{
int t,l=2;
scanf("%d",&t);
fo[0]=1;
fo[1]=2;
for(l=2;;l++)
{
fo[l]=fo[l-1]+fo[l-2];
if(fo[l]>=maxn) break;
}
for(int i=1;i<=t;i++)
{
scanf("%d%d",&m,&n);
for(int j=1;j<=n;j++)
scanf("%d%d%d",&edge[j].a,&edge[j].b,&edge[j].c);
int x1=solve(10);
if(x1!=m-1)
{
printf("Case #%d: No\n",i);
continue;
}
bool flag=0;
int x2=solve(0);
int x3=m-1-solve(1);
for(int j=0;j<=l;j++)
if(x2>=fo[j]&&x3<=fo[j])
flag=1;
if(flag) printf("Case #%d: Yes\n",i);
else printf("Case #%d: No\n",i);
}
return 0;
}