T1 组合数问题:
用k个不完全相同的组合数表示一个数n。
用k-1个1和一个n-k+1表示即可。
1 #include<cstdio> 2 using namespace std; 3 int x,k; 4 int main() 5 { 6 scanf("%d%d",&x,&k); 7 for (int i=1;i<k;i++) printf("%d %d ",i,0); 8 printf("%d %d ",x-k+1,1); 9 return 0; 10 }
T2 喵呜:
问从第x棵树的y高度,跳到第1棵或第n棵树的1或h高度,最少跳跃次数。
跳跃有两种:往左或往右跳a棵树,每次可以往上跳b高度,或往下跳b高度。不能出界。
如果可以跳出界,那么之后一定会跳回正常范围。所以可以证明在跳跃次数一定时必然可构造出不出界的方案。
然后对于四种方案讨论一下:设跳跃距离=k*a,跳跃高度差=g*b。当k>g时,设x为向上跳的次数,x-(g-x)=k,所以x=(k+g)/2,所以只要(k+g)%2=0,x就有整数解。
该方案的最小跳跃次数取max(k,g)。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const ll inf=1ll<<60; 6 ll read() 7 { 8 ll x=0;char ch=getchar(); 9 while (ch<'0'||ch>'9') ch=getchar(); 10 while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 11 return x; 12 } 13 ll n,h,x,y,a,b,Min; 14 void solve(ll k,ll g) 15 { 16 if ((k+g)%2==0) Min=min(Min,max(k,g)); 17 } 18 int main() 19 { 20 int T=read(); 21 while (T--) 22 { 23 n=read();h=read();x=read();y=read();a=read();b=read(); 24 if (abs(x-1)%a!=0&&abs(x-n)%a!=0||abs(y-1)%b!=0&&abs(y-h)%b!=0) {puts("-1");continue;} 25 Min=inf; 26 if (abs(x-1)%a==0&&abs(y-1)%b==0) solve(abs(x-1)/a,abs(y-1)/b); 27 if (abs(x-1)%a==0&&abs(y-h)%b==0) solve(abs(x-1)/a,abs(y-h)/b); 28 if (abs(x-n)%a==0&&abs(y-1)%b==0) solve(abs(x-n)/a,abs(y-1)/b); 29 if (abs(x-n)%a==0&&abs(y-h)%b==0) solve(abs(x-n)/a,abs(y-h)/b); 30 if (Min==inf) puts("-1");else printf("%lld ",Min); 31 } 32 return 0; 33 }
注意&&不要手滑写成||。
T3 白金元首与七彩魔法:
给你一个色盘,求两个点之间的一条线段上的所有点最大的亮度值(计算方式略)。
计算一下线段的斜率,然后用微分的思想算出顶点在线段上的直角三角形的斜边长和tan。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 const double pi=acos(-1); 6 int T,a[3],r[3]; 7 double Max,k,b,x[3],y[3]; 8 double calc(double r,double g,double b) 9 {return 0.3*r+0.59*g+0.11*b;} 10 double solve(double a,double r) 11 { 12 if (a<0) a+=360; 13 int h=a/60; 14 double f=a/60.0-h,p=1-r,q=1-f*r,t=1-(1-f)*r; 15 if (h==0) t=calc(1,t,p); 16 if (h==1) t=calc(q,1,p); 17 if (h==2) t=calc(p,1,t); 18 if (h==3) t=calc(p,q,1); 19 if (h==4) t=calc(t,p,1); 20 if (h==5) t=calc(1,p,q); 21 return t; 22 } 23 int main() 24 { 25 scanf("%d",&T); 26 while (T--) 27 { 28 scanf("%d%d%d%d",&a[1],&r[1],&a[2],&r[2]); 29 for (int i=1;i<=2;i++) 30 { 31 double g=a[i]/180.0*pi;//math库中的三角函数参数是弧度制 32 x[i]=cos(g)*r[i]/100.0; 33 y[i]=sin(g)*r[i]/100.0; 34 } 35 x[2]-=x[1];y[2]-=y[1];Max=0; 36 for (int i=0;i<=100000;i++)//切割 37 { 38 double X=x[1]+(double)i/100000.0*x[2]; 39 double Y=y[1]+(double)i/100000.0*y[2]; 40 Max=max(Max,solve(atan2(Y,X)/pi*180,sqrt(X*X+Y*Y))); 41 } 42 printf("%.4lf ",Max); 43 } 44 return 0; 45 }
注意不要把double开成int。
T4 组合数问题2:
求k个组合数的最大和,选取的每个组合数参数<=n且不完全相同。对1e9+7取模。
用一个大根堆维护组合数的大小。类似bfs从第n层中间那个往上方两个和左右扩展。
利用组合数的单调性还可以优化。
特技:用lgammal(x+1)-lgammal(y+1)-lgammal(x-y+1)可以比较出组合数的大小,避免卡精度。(这个东西好像是处理阶乘的log)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int mod=1e9+7; 5 const int N=1000005; 6 struct node{ 7 double x,y; 8 node(double A,double B) {x=A;y=B;} 9 }; 10 double calc(node A) 11 {return lgammal(A.x+1)-lgammal(A.y+1)-lgammal(A.x-A.y+1);} 12 struct cmp{ 13 bool operator () (const node &A,const node &B) 14 {return calc(A)<calc(B);} 15 }; 16 priority_queue<node,vector<node>,cmp> p; 17 int n,k,ans,jc[N],inv[N]; 18 map<int,int> mp[N]; 19 void init() 20 { 21 jc[0]=jc[1]=inv[0]=inv[1]=1; 22 for (int i=2;i<=n;i++) jc[i]=(ll)jc[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 23 for (int i=2;i<=n;i++) inv[i]=(ll)inv[i-1]*inv[i]%mod; 24 } 25 int c(int n,int m) {return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;} 26 int main() 27 { 28 scanf("%d%d",&n,&k);init(); 29 p.push(node(n,n/2));mp[n][n/2]=1; 30 for (int i=1;i<=k;i++) 31 { 32 node now=p.top();p.pop();int x=now.x,y=now.y; 33 int v=c(x,y); 34 ans=((ll)ans+v)%mod; 35 if (x>=1&&x-1>=y&&!mp[x-1][y]) p.push(node(x-1,y)),mp[x-1][y]=1;//注意边界限制! 36 if (x>=1&&y>=1&&!mp[x-1][y-1]) p.push(node(x-1,y-1)),mp[x-1][y-1]=1; 37 if (y>=1&&!mp[x][y-1]) p.push(node(x,y-1)),mp[x][y-1]=1; 38 if (y+1<=x&&!mp[x][y+1]) p.push(node(x,y+1)),mp[x][y+1]=1; 39 } 40 printf("%d ",ans); 41 return 0; 42 }
注意不要把取了模的东西扔进堆里比较。