题意:有一个机器人他的初始位置是1,在一个环形轨道上(轨道的长度n<=200),由于遥控器不太灵,机器人不太能准确的接受遥控的指令,遥控指令是让机器人顺时针或逆时针走w步,所以机器人有1/2的概率顺时针走w步,1/2的 概率逆时针走w步,题目就是要你算经过m(m<=1000000)次指令遥控后机器人最后停在某段轨道(L,R)的概率,这题我也没想出什么好办法,就暴力了,不断的WA,TLE,最后3500ms险过了(题目限时4000ms)
既然决定暴力,那么就是一步一步的算机器人走到轨道的某处的情况数了,可以一步步递推每次接到指令后就枚举轨道的位置,复杂度是n*m=2*10^8很凶残啊。。。。
输入格式是先输入 n,m,l,r,接下来再有m行输入指令的w值,若n,m,l,r,都是0则输入结束
需要注意的是所有的情况数将会非常庞大可以爆掉int,会WA,但是用long long 或double 或者float 都会TLE,没办法还是只能用int去保存情况总数,因为精度的要求不是特别高所以可以在他快要爆掉int的时候给他整体缩小一定的倍数,这样最后的比值是不会变太多的,ok,该说的都说完了
暴力开始代码如下:
注意用c++交会TLE,用G++交大概是3500ms
/********* PRO: hdu 4576 TIT: Robot DAT: 2013-08-10-13.22 AUT: UKean EMA: [email protected] *********/ #include<cstring> #include<algorithm> #include<cstdio> using namespace std; int way[205],temp[205], l,r,m,n,walk;//way数组存的是当前的轨道上到每处的情况总数,temp存的是上一次的轨道上的情况 int main() { while(scanf("%d%d%d%d",&n,&m,&l,&r)) { if(n+m+l+r==0) break; memset(way,0,sizeof way);//初始化当前的轨道 way[1]=1;//起点在 1 for(int i=0;i<m;i++) { scanf("%d",&walk); copy(way,way+n,temp); memset(way,0,sizeof(way)); for(int i=0;i<n;i++) if(temp[i])//上一步可以走到i则向左和右各走walk步 { way[(i+walk)%n]+=temp[i];//顺时针走 way[((i-walk)%n+n)%n]+=temp[i];//逆时针走 } int f=0;//因为情况数太多结果是会溢出的,f是快溢出的标记 for(int i=0;i<n;i++) if(way[i]>100000000) {f=1;break;} if(f) for(int i=0;i<n;i++) way[i]/=10;//如果有溢出的可能就把整个所有的情况数都除以10 } if(n==1) { printf("1.0000\n");continue;}//n为1是特殊情况要特判一下 long long sum=0,ans=0;//sum是总的情况数,ans是满足条件的情况数 for(int i=0;i<n;i++) sum+=way[i]; for(int i=l;i<=r;i++) ans+=way[i%n]; printf("%.4lf\n",(1.0*ans)/(double)sum); } return 0; }
无注释版
/********* PRO: hdu 4576 TIT: robot DAT: 2013-08-10-13.22 AUT: UKean EMA: [email protected] *********/ #include<cstring> #include<algorithm> #include<cstdio> #include<iostream> using namespace std; int way[205]; int temp[205]; int l,r,m,n,walk; int main() { while(scanf("%d%d%d%d",&n,&m,&l,&r)) { if(n+m+l+r==0) break; memset(way,0,sizeof way); way[1]=1; for(int i=0;i<m;i++) { scanf("%d",&walk); copy(way,way+n+2,temp); memset(way,0,sizeof(way)); for(int i=0;i<n;i++) if(temp[i]) { way[(i+walk)%n]+=temp[i]; way[((i-walk)%n+n)%n]+=temp[i]; } int f=0; for(int i=0;i<n;i++) if(way[i]>100000000) {f=1;break;} if(f) for(int i=0;i<n;i++) way[i]/=10; } if(n==1) { printf("1.0000\n"); continue; } long long sum=0,ans=0; for(int i=0;i<n;i++) sum+=way[i]; for(int i=l;i<=r;i++) ans+=way[i%n]; //cout<<"ans "<<ans<<" sum "<<sum<<endl; printf("%.4lf\n",(1.0*ans)/(double)sum); } return 0; }
转载的别人的代码:我的太暴力,太没技术含量了,转一下大神的代码仰慕一下,哈哈
这个题目看网上好多题解都是直接O(n*m)卡过。我是这么做的。 对于m次操作,统计每个w的次数。然后对每个w做矩阵乘法。 这样直接做矩阵乘法是会TLE的。 又由于这里的矩阵很特殊,一次乘法可以降维成O(n^2)。 -------------------------- 怎么降维的可以这样模拟下: a b c a b c a*a+2bc c*c+2ab b*b+2ac c a b * c a b = b*b+2ac a*a+2bc c*c+2ab b c a b c a c*c+2ab b*b+2ac a*a+2bc 注意到原矩阵的每一行(除了第一行)都是上一行向右平移一个单位的结果,而相乘得到的矩阵也满足这个性质。 那么做一次矩阵乘法的时候,就只用算出结果矩阵的第一行,然后下面的每一行直接可由上一行得到。 复杂度降为了O(n^2)。 -------------------------
#include<cstdio> #include<iostream> #include<iomanip> #include<cstring> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<string> #include<vector> #include<ctype.h> #include<algorithm> using namespace std; typedef long long LL; #define FF(i,x) for(i=1;i<=x;i++) const int N = 205; double cMat[N][N],retMat[N][N]; void matrixMul1(double A[][N],double B[][N],int a,int b) { double buff[N][N]={}; int i,j,k; FF(i,a) FF(k,a) FF(j,b) buff[i][j] = buff[i][j] + A[i][k]*B[k][j]; FF(i,a) FF(j,b) B[i][j]=buff[i][j]; } void matrixMul2(double A[][N],double B[][N],int a,int b) { double buff[N][N]={}; for(int j=1;j<=a;j++) { for(int k=1;k<=a;k++) buff[1][j]+=A[1][k]*B[k][j]; } for(int i=2;i<=a;i++) { for(int j=2;j<=a;j++) buff[i][j]=buff[i-1][j-1]; buff[i][1]=buff[i-1][a]; } int i,j; FF(i,a) FF(j,b) B[i][j]=buff[i][j]; } void matrixFastPow(int p,int n) { for(;p;p>>=1) { if( p&1 ) matrixMul1(cMat,retMat,n,1); matrixMul2(cMat,cMat,n,n); } } int amount[105]; int main() { int n,m,l,r; int w; while( scanf("%d%d%d%d",&n,&m,&l,&r),n||m||l||r ) { memset(amount,0,sizeof(amount)); for(int i=0;i<m;i++) { scanf("%d",&w); amount[w]++; } for(int i=1;i<=n;i++) if( i<l || i>r ) retMat[i][1]=0.0; else retMat[i][1]=1.0; for(int i=1;i<=100;i++) if( amount[i] ) { for(int p=1;p<=n;p++) for(int q=1;q<=n;q++) cMat[p][q]=0.0; for(int j=1;j<=n;j++) { int a=(j-i); while( a<=0 ) a+=n; int b=(j+i); while( b>n ) b-=n; cMat[j][a]+=0.5; cMat[j][b]+=0.5; } matrixFastPow(amount[i],n); } printf("%.4f\n",retMat[1][1]); } return 0; }
所以一个总的复杂度<O(n^2 * log1000000 * 100)=8千万. 不到2000msAC了^_^