250pt
数学模型:
求顶角是120度的等腰三角形的面积
分析:
L*L*sqrt(3.0)/4.0,
计算的时候为了提高精度,先乘后除。
class MinimalTriangle { public: double maximalArea(int length) { double l=length,t=sqrt(3.0); return l*l*t/4.0; } };
500pt
数学模型:
给定n组点,每组横坐标相同,第一组:(0,1),(0,2)......(0,h[0]);.......第组:((n-1)*w,1),((n-1)*w,2)......((n-1)*w,h[n-1]),相邻两组的的横坐标相差w。在每组中任选一个点,连接相邻两组所选的点,求这条折线的总长。
分析:比赛时猜想贪心,但证明不了,赛后证明是错的,还是用DP稳妥点
1,枚举每组的每个点
dp[i][j]表示选定第i组纵坐标为j的点时最长折线长度
dp[i][j]=(dp[i-1][k],hypot(k-j,w))(1<=k<=h[i-1]);复杂度O(N^3)
2,赛后看有人是贪心加动态规划做的,每次只用考虑每组的最高点和最低点。
和它们之间的状态转移,复杂度是O(n)。
结:SRM比赛中,在时间限制内,编写出尽量正确且容易编写的代码,正确和短码的优先级比效率要高
此方法可扩展到二维?
枚举+动态规划
class PillarsDivTwo { public: double maximalLength(vector <int> h, int w) { int i,j,k,n=h.size(); double dp[60][110]={0}; if(n==1) return 0.0; for(i=1;i<n;i++) for(j=1;j<=h[i];j++) for(k=1;k<=h[i-1];k++) dp[i][j]=max(dp[i][j],dp[i-1][k]+hypot(abs(j-k)*1.0,w*1.0)); for(j=k=1;j<=h[n-1];j++) if(dp[n-1][j]>dp[n-1][k]) k=j; return dp[n-1][k]; } };
贪心+动态规划
class PillarsDivTwo { public: double maximalLength(vector <int> h, int w) { int i,j,k,n=h.size(); double dp[111][2]={0}; for(i=1;i<n;i++) { dp[i][0]=max(dp[i-1][0]+w,dp[i-1][1]+hypot(h[i-1]-1,w)); dp[i][1]=max(dp[i-1][0]+hypot(h[i]-1,w),dp[i-1][1]+hypot(1.0*abs(h[i-1]-h[i]),w)); } return max(dp[n-1][0],dp[n-1][1]); } };
1000pt
数学模型:
给定一个数值范围是1到100的整数集合,求一个子集,使元素互质且个数最多。
分析:比赛的时候没想太多,直接深度优先搜索枚举每个子集,再加优化。但是犯了一个致命错误:当1左移的结果是long long时,应该是强制转为long long ,即(long long)1;赛后改了但是超时,看别人代码居然是状态压缩动态规划,我当时想过但觉得会超时。
重新读题,发现没有充分利用范围是1到100这个条件,再考虑互质的本质:即有除1以外的公约数,任何整数都可以由质数的连乘组成,那么互质就是有公约数,而且公约是是质数,即可以用质数的集合来表示这些整数,如24,可用{2,3},整数的互质就可用交集为空来表示,而这些集合最多有25个元素(100以内有25个质数),但是状态数太多,会超时;再看50以上的质数与所有其它的数都互质,所以可以预处理,那么只剩下15个,集合可用一个整数(0~(1<<15)-1)表示,每个二进制位表示一个元素,1没有该元素,0表示已有该元素。
结:读题要仔细,充利用题目条件,条件不同,算法完全不同
class RelativelyPrimeSubset { public: long long n,b[55]; int ans; int gcd(int a,int b) { return b?gcd(b,a%b):a; } void DFS(long long k,int cnt,long long t) { if(k==n) { ans=max(ans,cnt); return ; } if(cnt+n-k<=ans) return ; if(t&((long long)1<<k)) DFS(k+1,cnt+1,t&b[k]); DFS(k+1,cnt,t); } int findSize(vector <int> a) { long long i,j; n=(long long)a.size(); ans=1; for(i=0;i<n;i++) for(j=0,b[i]=0;j<n;j++) if(gcd(a[i],a[j])==1) b[i]|=((long long)1<<j); for(i=0;i<n;i++) DFS(i+1,1,b[i]); return ans; } };
O(N*(1<<15))
class RelativelyPrimeSubset { public: int f[1<<15]; int findSize(vector <int> S) { int i,j,k,n,m,ret,empty,c[51],a[111]={0},p[111],d[51]; bool b[51]={false}; for(i=2;i<100;i++) if(!a[i]) { for(j=i+i;j<=100;j+=i) a[j]=1; } m=0; sort(S.begin(),S.end()); if(S[0]==1) m++,S.erase(S.begin()); n=S.size(); for(i=0;i<n;i++) if(!a[S[i]]) { m++; for(j=i;j<n;j++) if(S[j]%S[i]==0) b[j]=true; } for(i=j=0;i<n;i++) if(!b[i]) { c[j++]=S[i]; printf("%d ",S[i]); for(k=2;k<100;k++) if(!a[k]&&S[i]%k==0) a[k]=-1; } n=j; if(!n) return m; for(i=2,k=0;i<100;i++) if(a[i]==-1) p[k++]=i; for(i=0;i<n;i++) for(d[i]=j=0;j<k;j++) if(c[i]%p[j]==0) d[i]|=(1<<j); memset(f,0,sizeof(f)); empty=(1<<k); for(i=empty-1;i>=0;i--) for(j=0;j<n;j++) if((i&d[j])==0) f[i]=max(f[i^d[j]]+1,f[i]); ret=0; for(i=0;i<empty;i++) ret=max(f[i],ret); return ret+m; } };