1001 GSM
一道计算几何题,学长用Voronoi图模板做的,表示不太会。直接用递归二分找所有最短的点,1000多MS,慢是慢了点,不过也能过。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#define N 1e18
#define exp 1e-7
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
struct xl
{
double a,b;
}c[55],s[55];
int n,m;
int zero(double x)//double数判正负
{
return x>exp?1:(x<-exp?-1:0);
}
double d(xl p,xl q)
{
return (p.a-q.a)*(p.a-q.a)+(p.b-q.b)*(p.b-q.b);
}
int g(xl t)
{
int id,i;
double ds=N,tmp;
for(i=0;i<m;++i)
{
tmp=d(t,s[i]);
if(zero(tmp-ds)<0)
{
ds=tmp;
id=i;
}
}
return id;
}
int f(xl p,xl q)//二分求解
{
int l=g(p),r=g(q);
xl m;
double ds;
if(l==r)
{
return 0;
}
else
{
ds=d(p,q);
if(zero(ds)==0)
{
return 1;
}
m.a=(p.a+q.a)/2.0;
m.b=(p.b+q.b)/2.0;
return f(p,m)+f(m,q);
}
}
int main()
{
int i,q,x,y,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<n;++i)
{
scanf("%lf%lf",&c[i].a,&c[i].b);
}
for(i=0;i<m;++i)
{
scanf("%lf%lf",&s[i].a,&s[i].b);
}
RD(q);
while(q--)
{
RD(x);
RD(y);
ans=f(c[x-1],c[y-1]);
OT(ans);
printf("\n");
}
}
return 0;
}
1004 Laser Beam
恶心的题啊,我无数次的WA,TLE,MLE,RE。各种卡。。。最后才过的。
解题报告上说只要枚举(n+3)/2边上的红点就行可以了,O(n)能过的,,可我就是再优化,也还是TLE。。。用标程的DFS过居然是0MS,,,没办法只能再想办法,最后加了各种调用优化,才终于算过了,也有一点递归。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
map<int,int>dp;
int gcd(int a,int b)
{
if(b==0)
{
return a;
}
else
{
return gcd(b,a%b);
}
}
int g(int x)
{
if(x==1)
{
return 1;
}
int i,m=0,p=-1,q=-1,j,id,jd;
for(i=1; i<=x; i+=3)
{
j=(x+3)-4*i;
if(j<=0)
{
break;
}
if(j%6==0)
{
j=j/6;
p=i;
q=j;
break;
}
id=i+1;
jd=(x+3)-4*id;
if(jd<=0)
{
break;
}
if(jd%6==0)
{
jd=jd/6;
p=id;
q=jd;
break;
}
}
if(p>0)
{
while(q>0)
{
if(gcd(p,q)==1)
{
m++;
}
p+=3;
q-=2;
}
}
return m*2;
}
void f()
{
dp.clear();
int i;
dp[4]=1;
dp[3]=dp[2]=dp[1]=dp[0]=0;
for(i=1; i<=100; ++i)
{
dp[i+3]=g(i);
}
}
int c(int x)
{
int i,j;
if(x%2!=0)
{
return 0;
}
for(i=1;; ++i)
{
if((x-i*4)%6==0)
{
j=(x-i*4)/6;
break;
}
}
if(j<=0)
{
return 0;
}
return (j+1)/2;
}
int d(int x)
{
int i;
if(dp.count(x))
{
return dp[x];
}
if((x-3)%6!=1&&(x-3)%6!=5)
{
return 0;
}
dp[x]=c(x)*2;
for(i=2; i*i<=x; ++i)
{
if(x%i==0)
{
if(i>4)
{
dp[x]-=d(i);
}
if(x/i>4&&i*i<x)
{
dp[x]-=d(x/i);
}
}
}
return dp[x];
}
int main()
{
int t,n,ans;
f();
RD(t);
while(t--)
{
scanf("%d",&n);
ans=d(n+3);
printf("%d\n",ans);
}
return 0;
}
1005 Another Graph Game
想法题,谨以此题向Baoge致敬。。。a+b的难度了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
bool cmp(double a,double b)
{
return a>b;
}
int main()
{
int n,m,u,v,i;
double w,s[100001],a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;++i)
{
scanf("%lf",&s[i]);
}
for(i=1;i<=m;++i)
{
scanf("%d%d%lf",&u,&v,&w);
s[u]+=w/2.0;
s[v]+=w/2.0;
}
sort(s+1,s+n+1,cmp);
a=0;
b=0;
for(i=1;i<=n;++i)
{
if(i%2==1)
{
a+=s[i];
}
else
{
b+=s[i];
}
}
printf("%.0f\n",a-b);
}
return 0;
}
1006 Magic Pen 6
签到题,求最大能整除M的区间。O(n^2)已能过。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
int a[100001];
int main()
{
int n,m,i,j,s,x;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(a,0,sizeof(a));
for(i=1;i<=n;++i)
{
scanf("%d",&x);
a[i]=(a[i-1]+x)%m;
}
s=0;
for(i=n;i>=1&&i>s;--i)
{
for(j=1;j<=n-i+1;++j)
{
if((a[j+i-1]-a[j-1])%m==0)
{
s=max(s,i);
break;
}
}
}
printf("%d\n",s);
}
return 0;
}
1007 Professor Tian
我们唯一没过的版刷题,一道水概率DP,将数字转化为二进制,总共就20次转化,然后对‘1’,‘0’用二维数组标记,对相应的运算符进行计算。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
int a[201];
double p[201],dp[201][2];
char s[201];
int main()
{
int n,i,j,cas=0,x;
double sum,pw;
while(scanf("%d",&n)!=EOF)
{
cas++;
for(i=0; i<=n; ++i)
{
RD(a[i]);
}
for(i=1; i<=n; ++i)
{
cin>>s[i];
}
for(i=1; i<=n; ++i)
{
scanf("%lf",&p[i]);
}
pw=1.0;
sum=0.0;
for(i=0; i<=20; ++i)
{
dp[0][1]=((a[0]>>i)&1);
dp[0][0]=!dp[0][1];
for(j=1; j<=n; ++j)
{
dp[j][1]=dp[j-1][1]*p[j];
x=((a[j]>>i)&1);
if(s[j]=='^')
{
dp[j][1]+=(dp[j-1][0]*(0^x)+dp[j-1][1]*(1^x))*(1.0-p[j]);
}
else if(s[j]=='&')
{
dp[j][1]+=(dp[j-1][0]*(0&x)+dp[j-1][1]*(1&x))*(1.0-p[j]);
}
else if(s[j]=='|')
{
dp[j][1]+=(dp[j-1][0]*(0|x)+dp[j-1][1]*(1|x))*(1.0-p[j]);
}
dp[j][0]=1.0-dp[j][1];
}
sum+=pw*dp[n][1];
pw*=2.0;
}
printf("Case %d:\n%.6f\n",cas,sum);
}
return 0;
}
1009 Partition
一道老题了,整数划分的情况整数,可以通过维基百科和数列公式了解一下。。。由于它没有相应的唯一公式,所以只能通过递推的方式得到。
f(n)+={f(n-i*(3*i-1))+f(n-i*(3*i+1))}*(-1)^(i+1)
加上或减去的项数为五角数公式;
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
long long a[100001];
void f()
{
int i,j;
long long sum;
a[0]=1;
a[1]=1;
a[2]=2;
for(i=2;i<=100000;++i)
{
sum=0;
for(j=1;(i-j*(3*j-1)/2)>=0||(i-j*(3*j+1)/2)>=0;j++)//递推式
{
if(j%2==1)
{
if((i-j*(3*j-1)/2)>=0)//注意两个都是if
{
sum+=a[(i-j*(3*j-1)/2)]%N;
}
if((i-j*(3*j+1)/2)>=0)
{
sum+=a[(i-j*(3*j+1)/2)]%N;
}
}
else
{
if((i-j*(3*j-1)/2)>=0)
{
sum=(sum-a[(i-j*(3*j-1)/2)]+N)%N;//防止为负数,我因为这个WA了
}
if((i-j*(3*j+1)/2)>=0)
{
sum=(sum-a[(i-j*(3*j+1)/2)]+N)%N;
}
}
}
a[i]=sum;
}
}
int main()
{
f();
int t,n;
RD(t);
while(t--)
{
cin>>n;
cout<<a[n]%N<<endl;
}
return 0;
}
1011 k-th point
公式题,不解释,知道你就能AC,不知道的只能寄希望于强悍的数学推导能力或者YY猜公式的能力。。。
我YY到公式时,学长也正好找到了公式:i*p/(i*p+1)连乘 (i=>n-k~n)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define exp 1e-10
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}
while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
{
OT(a/10);
}
putchar(a%10+'0');
}
int main()
{
int t,n,k,i;
double sum,p;
RD(t);
while(t--)
{
cin>>p>>n>>k;
sum=1.0;
for(i=n-k;i<=n;++i)
{
sum=sum*(i*p)/(i*p+1.0);
}
printf("%.9f\n",sum);
}
return 0;
}
这次表现不错,但还是差距很大。。。继续努力!