测试题--by 罗雨屏

来源:互联网 发布:怎么避免mac涂层脱落 编辑:程序博客网 时间:2024/06/14 04:46

T1:

就是给你平面上的n个点,要你求个最小方差生成树

这题完全不会做,搜了题解才恍然大悟,简直巧妙

首先假设知道选的边权的平均数是a,那么就把新边权定位(v-a)^2(v是原来的边权),再做一遍最小生成树就行了

然后我们发现,影响最小生成树的不是边权,而是边权的相对大小关系(从kruskal上很好理解)

想象两条边v1,v2,当a从<(v1+v2)/2变化到a>(v1+v2)/2时,这两条边的大小关系发生变化,于是把m^2个变化点搞出来,分别做一遍最小生成树就Ok了

复杂度O(m^2*n^2)

#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int maxn=25;int n,x[maxn],y[maxn];void init(){scanf("%d",&n);for (int i=1;i<=n;++i) scanf("%d",x+i);for (int i=1;i<=n;++i) scanf("%d",y+i);}double e[maxn*maxn];double w[maxn*maxn*maxn*maxn];double ans;void gao(double d[]){double res=0;for (int i=2;i<=n;++i) res+=d[i];res/=n-1; double s=0;for (int i=2;i<=n;++i) s+=(d[i]-res)*(d[i]-res);s=s/(n-1); if (s<ans) ans=s;}inline double getdist(int a,int b){return sqrt(1.0*(x[a]-x[b])*(x[a]-x[b])+1.0*(y[a]-y[b])*(y[a]-y[b]));}void prim(double x){static double d[maxn],dist[maxn]; static bool vis[maxn];memset(vis,0,sizeof(vis)); for (int i=0;i<=n;++i) dist[i]=1e20;dist[1]=0;for (int i=1;i<=n;++i){int tmp=0; for (int i=1;i<=n;++i) if (!vis[i] && dist[i]<dist[tmp]) tmp=i;vis[tmp]=1;for (int i=1;i<=n;++i) if (!vis[i]){double res=getdist(tmp,i)-x;if (res*res<dist[i]){dist[i]=res*res; d[i]=getdist(tmp,i);}}}gao(d);}void work(){int m=0; ans=1e20;for (int i=1;i<=n;++i)for (int j=i+1;j<=n;++j) e[++m]=getdist(i,j);int t=0; for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j) w[++t]=(e[i]+e[j])/2;sort(w+1,w+t+1); prim(0);for (int i=1;i<t;++i) prim((w[i]+w[i+1])/2); prim(w[t]+1);printf("%.3f\n",sqrt(ans));}int main(){freopen("mst.in","r",stdin); freopen("mst.out","w",stdout);int T; scanf("%d",&T);while (T--) init(),work();return 0;}

T2:

有一只狐狸在原点上,方向朝着x轴正方向,每过一单位时间,每只狐狸都会分裂成(S+L+R)只,其中S只前进一步,L只原地左转,R只原地右转,每只狐狸的贡献是它所在的坐标的横纵坐标的积,要你求t时间后,所有狐狸的贡献是多少    S,L,R<=10^9   t<=10^18  还有多组数据,组数<=30

又是一道蘑菇题。。。

维护一个13*13的矩阵,分别代表方向为上下左右的sigma(x),sigma(y),cnt,还有一个记录当前的总贡献,这样矩阵乘法就Ok了,至于转移什么的很简单,就是很多。。。

#include<vector>#include<cstdio>#include<cassert>#include<cstring>#include<iostream>using namespace std;typedef long long ll;//const int dx[]={1,0,-1,0},dy[]={0,-1,0,1};const int mod=1000000007;ll n; int S,L,R;struct Tmx{ll a[14][14];void clear(){memset(a,0,sizeof(a));}void xxx(){clear();a[0][0]=S; a[3][0]=L; a[9][0]=R;a[1][1]=S; a[2][1]=S; a[4][1]=L; a[10][1]=R;a[2][2]=S; a[5][2]=L; a[11][2]=R;a[0][3]=R; a[3][3]=S; a[5][3]=S; a[6][3]=L;a[1][4]=R; a[4][4]=S; a[7][4]=L;a[2][5]=R; a[5][5]=S; a[8][5]=L;a[3][6]=R; a[6][6]=S; a[9][6]=L;a[4][7]=R; a[7][7]=S; a[8][7]=-S; a[10][7]=L;a[5][8]=R; a[8][8]=S; a[11][8]=L;a[0][9]=L; a[6][9]=R; a[9][9]=S; a[11][9]=-S;a[1][10]=L; a[7][10]=R; a[10][10]=S;a[2][11]=L; a[8][11]=R; a[11][11]=S;a[0][12]=S; a[4][12]=S; a[6][12]=-S; a[10][12]=-S;a[12][12]=(0LL+S+L+R)%mod;}}I;void mul(Tmx &c,Tmx b){Tmx a=c; c.clear();for (int i=0;i<13;++i) for (int j=0;j<13;++j)for (int k=0;k<13;++k) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;}Tmx power(Tmx a,ll t){Tmx res=I;for (;t;t>>=1,mul(a,a))if (t&1) mul(res,a);return res;}int main(){freopen("fox.in","r",stdin); freopen("fox.out","w",stdout);I.clear(); for (int i=0;i<14;++i) I.a[i][i]=1;int T; cin>>T;while (T--){cin>>n>>S>>L>>R;Tmx a; a.xxx(); a=power(a,n);Tmx b; b.clear(); b.a[0][5]=1; mul(b,a);printf("%d\n",(b.a[0][12]%mod+mod)%mod);}


T3:

给你一个2*m的格子,每个格子需要填进1,2,3中的一个,要求相同的数字不能相邻,且每个2*2的格子中3个数都必须有,还限定了1,2,3的个数a,b,c  保证a+b+c=2*m

这题很巧妙(碰巧今天ZJOI的讲课上也讲了),首先意识到前一列确定了,那么自己这一列就还剩下一个必须选的,如果我们知道了每一列必须选的是谁,那么我们就可以构造出两种原染色方案(且不重不漏),于是问题变成用1,2,3填一列数,相同的不相邻的方案数(1,2,3的个数任然确定,用原来的接一下方程就知道了)

接下来就有很多种方法了,说的可能不是很清楚  去膜拜 http://blog.csdn.net/maverick1990/article/details/16954151 吧

#include<cmath>#include<cstdio>#include<cassert>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int mod=1000000007,maxm=1000011;int m,R,G,B;void init(){scanf("%d%d%d%d",&m,&R,&G,&B);}int power(int x,int t){int res=1;for (;t;t>>=1,x=1LL*x*x%mod)if (t&1) res=1LL*res*x%mod;return res;}int fact[maxm],nfac[maxm];inline int C(int n,int m){return 1LL*fact[n]*nfac[m]%mod*nfac[n-m]%mod;}int Query(int x,int y,int z){if (!x && !y && !z) return 1;if (!x || z>x+y) return 0;int res=0; int lim=min(x,y);for (int k=0;k<=lim;++k){if (!k && y) continue;if (z<(x-k)+(y-k)) continue;int a=C(x,k),b,c;if (!y) b=1; if (k>=1) b=C(y-1,k-1);c=C(2*k,z-(x-k)-(y-k));res=(res+1LL*a*b%mod*c%mod)%mod;}return res;}void work(){fact[0]=1; for (int i=1;i<=m;++i) fact[i]=1LL*fact[i-1]*i%mod;nfac[m]=power(fact[m],mod-2);for (int i=m-1;i>=0;--i) nfac[i]=nfac[i+1]*(i+1LL)%mod;int x=m-R,y=m-B,z=m-G;if (x<0 || y<0 || z<0){puts("0"); return;}if (x<y) swap(x,y); if (x<z) swap(x,z); if (y<z) swap(y,z); // z<=y<=xint res=(0LL+Query(x+1,y,z)+Query(x,y,z)*2+Query(x-1,y,z))%mod;printf("%d\n",(res+res)%mod);}int main(){freopen("board.in","r",stdin); freopen("board.out","w",stdout);int T; cin>>T;while (T--) init(),work();return 0;}


0 0
原创粉丝点击