2017-2-17第一周周赛题解
A题很水的几何题
套一下向量的旋转公式即可
1 #include<stdio.h> 2 #include<queue> 3 #include<math.h> 4 using namespace std; 5 const double PI=acos(-1); 6 struct Node 7 { 8 double x,y; 9 int angel; 10 void rotate() 11 { 12 double t=angel*PI/180,a; 13 a=cos(t)*x-sin(t)*y; 14 y=sin(t)*x+cos(t)*y; 15 x=a; 16 } 17 }vec; 18 int main() 19 { 20 int t,x,n; 21 char op[10]; 22 while(scanf("%lf%lf%d",&vec.x,&vec.y,&vec.angel)!=EOF) 23 { 24 vec.rotate(); 25 printf("%f %f\n",vec.x,vec.y); 26 } 27 return 0; 28 }
B题
也是大水题,虽然题目说了那么长,但其实置换乘法,仅仅只是映射的复合而已,若p1代表的映射是f1,p2代表的映射是f2,
那么两个置换做乘法的结果所代表的映射就是f1(f2(i))。
这题求一下逆映射就行了。
1 #include<stdio.h> 2 #include<queue> 3 #include<math.h> 4 using namespace std; 5 int inv[50]; 6 int main() 7 { 8 int t,x,n,i; 9 char op[10]; 10 while(scanf("%d",&n)!=EOF) 11 { 12 for(i=1;i<=n;i++) 13 { 14 scanf("%d",&x); 15 inv[x]=i; 16 } 17 for(i=1;i<=n;i++) 18 { 19 if(i>1) 20 printf(" "); 21 printf("%d",inv[i]); 22 } 23 puts(""); 24 } 25 return 0; 26 }
C题
C题也比较水,在理解清楚置换的概念之后,可以发现置换乘法仅仅是映射的复合而已,每次乘法都可以在O(n)时间内搞定
,然后写个快速幂就行了。
1 #include<stdio.h> 2 #include<queue> 3 #include<math.h> 4 using namespace std; 5 struct ZhiHuan 6 { 7 int arr[30],size; 8 void mul(ZhiHuan b) 9 { 10 int i; 11 for(i=1; i<=size; i++) 12 arr[i]=b.arr[arr[i]]; 13 } 14 void put() 15 { 16 int i; 17 for(i=1; i<=size; i++) 18 { 19 if(i>1) 20 printf(" "); 21 printf("%d",arr[i]); 22 } 23 puts(""); 24 } 25 } e,a,b; 26 ZhiHuan pow(ZhiHuan a,int n) 27 { 28 ZhiHuan ans=e; 29 while(n) 30 { 31 if(n&1) 32 ans.mul(a); 33 a.mul(a); 34 n>>=1; 35 } 36 return ans; 37 } 38 int main() 39 { 40 int t,x,n,i,m; 41 char op[10]; 42 for(i=1;i<30;i++) 43 e.arr[i]=i; 44 while(scanf("%d%d",&n,&m)!=EOF) 45 { 46 a.size=n; 47 e.size=n; 48 for(i=1;i<=n;i++) 49 { 50 scanf("%d",&a.arr[i]); 51 } 52 b=pow(a,m); 53 b.put(); 54 } 55 return 0; 56 }
D题:
首先我先构造递推表达式
其中E是单位阵,O是零矩阵
我们发现这和线性递推式很像,只是特殊在系数是矩阵而已。
我把这个递推式的矩阵写出来
这时我们发现,这个递推式可以用分块阵来表示,在配合快速幂求一下这个分块阵的n次方就能轻松求出Sn
这里有个小技巧,我们很容发现分块阵的任何次方中,右上永远是零矩阵,右下永远是单位阵。用这个特性能化简一些计算过程
下面是47ms的代码,复杂度(log(k)*n^3)
1 #include<stdio.h> 2 #include<string.h> 3 #define Nmax 10100 4 int mod,degree; 5 struct matrix 6 { 7 int m[40][40]; 8 void put() 9 { 10 int i,j; 11 for(i=0; i<degree; i++) 12 { 13 for(j=0; j<degree; j++) 14 { 15 if(j) 16 printf(" "); 17 printf("%d",m[i][j]); 18 } 19 puts(""); 20 } 21 } 22 matrix operator *(const matrix &b)const 23 { 24 matrix ans; 25 memset(ans.m,0,sizeof(ans.m)); 26 int i,j,k; 27 for(i=0; i<degree; i++) 28 { 29 for(j=0; j<degree; j++) 30 { 31 for(k=0; k<degree; k++) 32 { 33 ans.m[i][j]+=m[i][k]*b.m[k][j]; 34 } 35 ans.m[i][j]%=mod; 36 } 37 } 38 return ans; 39 } 40 matrix operator +(const matrix &b)const 41 { 42 matrix ans; 43 int i,j; 44 for(i=0; i<degree; i++) 45 { 46 for(j=0; j<degree; j++) 47 ans.m[i][j]=(m[i][j]+b.m[i][j])%mod; 48 } 49 return ans; 50 } 51 } E,O; 52 struct BigMat 53 { 54 matrix A,B,C,D; 55 }; 56 void matpow(matrix p,int n) 57 { 58 BigMat temp,ans; 59 matrix A,C; 60 ans.A=E;ans.B=O; 61 ans.C=O;ans.D=E;; 62 temp.A=p;temp.B=O; 63 temp.C=E;temp.D=E; 64 while(n) 65 { 66 if(n&1) 67 { 68 A=ans.A*temp.A; 69 C=ans.C*temp.A+temp.C; 70 ans.A=A; 71 ans.C=C; 72 } 73 n>>=1; 74 A=temp.A*temp.A; 75 C=temp.C*temp.A+temp.C; 76 temp.A=A; 77 temp.C=C; 78 } 79 A=ans.C*p; 80 A.put(); 81 } 82 int main() 83 { 84 85 int i,n,k,j,x,l; 86 matrix a; 87 memset(E.m,0,sizeof(E.m)); 88 for(i=0; i<40; i++) 89 E.m[i][i]=1;/**初始化单位阵*/ 90 memset(O.m,0,sizeof(O.m));/**初始化零矩阵*/ 91 scanf("%d%d%d",&n,&k,&mod); 92 for(i=0; i<n; i++) 93 { 94 for(j=0; j<n; j++) 95 { 96 scanf("%d",&x); 97 a.m[i][j]=x%mod; 98 } 99 } 100 degree=n; 101 matpow(a,k); 102 return 0; 103 }
E题
考查线段树,我们在区间[l,r]上存下这一区间x分量,y分量。更新时用角度当成标记是大家首先都能想到的。所以我们要在每个节点存下三个angle,x,y.分别代表这一区间的共同旋转过的角度,和这区间旋转共同角度后的x分量和y分量。
但这题比较麻烦的地方在于,虽然角度是线性叠加的,但x,y上的分量计算时是非线性的,而题目要求要查询的是x,y的分量、所以为了解决这困难。更新时先把标记下放,然后更新标记,最后再从下往上更新x,y分量就行了。查询时查询顶部节点就可以了。这里有个小技巧,为了提高运算速度可以先将sin,和cos先都预处理好
我线段树用的是完全二叉树形式的数组实现。
用时1204ms,复杂度(2n+c*log(n))
#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<math.h> #include<algorithm> using namespace std; #define come_first min #define INF 2e9 const double PI=acos(-1.0); double SIN[365],COS[365]; struct Node { double x,y; int angle; void rotate() { angle=angle%360; if(angle<0) angle+=360; double temp; temp=COS[angle]*x-SIN[angle]*y; y=SIN[angle]*x+COS[angle]*y; x=temp; } }; int len[10005],a[10005]; struct Segment_tree { static const int maxn=2<<15; int size,temp; Node node[maxn]; void build(int n) { n+=2; size=1; while(size<n) size<<=1; memset(node,0,sizeof(node)); } void build(int n,int a[]) { int i,h=1,m; build(n); for(i=1; i<=n; i++) { node[i+size].y=a[i]; } m=n+size; for(i=size-1; i>0; i--) { if(i<<h<=m) { if(i<<h==size) h++; node[i].x=node[i+i].x+node[i+i+1].x; node[i].y=node[i+i].y+node[i+i+1].y; } } node[0].angle=0; } void putdown(int s,int t)///将标记放下 { if(s^1) { putdown(s>>1,t>>1); } if(node[s].angle) { node[s<<1].angle+=node[s].angle; node[(s<<1)+1].angle+=node[s].angle; node[s].angle=0; } if(node[t].angle) { node[t<<1].angle+=node[t].angle; node[(t<<1)+1].angle+=node[t].angle; node[t].angle=0; } } void update(int pos) { temp=pos<<1; if(pos<size) { node[pos].x=node[temp].x+node[temp+1].x; node[pos].y=node[temp].y+node[temp+1].y; } else { node[pos].x=0; node[pos].y=len[pos-size]; } if(node[pos].angle) node[pos].rotate(); } void add(int l,int n,int angle)///更新 { int s=l+size,t=n+size+1; putdown(s>>1,t>>1); for(; s^t^1; s>>=1,t>>=1) { if(~s&1) { node[s^1].angle+=angle; } update(s); update(s^1); if(t&1) { node[t^1].angle+=angle; } update(t); update(t^1); } update(s); update(t); while(s>1) { update(s>>1); s>>=1; } } } tree; int main() { int i,j,n,m,x,y,d,t=1,cas=0,angle; double arc; for(i=0; i<360; i++) { arc=(double)i*PI/180; SIN[i]=sin(arc); COS[i]=cos(arc); } while(scanf("%d%d",&n,&m)!=EOF) { if(cas) { puts(""); } cas++; memset(len,0,sizeof(len)); for(i=1; i<=n; i++) { scanf("%d",&len[i]); a[i]=180; } tree.build(n,len); while(m--) { scanf("%d%d",&x,&angle); tree.add(x,n,angle-a[x]); a[x]=angle; printf("%.2f %.2f\n",tree.node[1].x,tree.node[1].y); } } return 0; }
再丧心病狂加了一堆优化后,加外输入输出优化
用时141ms
#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<math.h> #include<algorithm> using namespace std; #define come_first min #define INF 2e9 const double PI=acos(-1.0); double SIN[365],COS[365]; struct Node { double x,y; int angle; void rotate() { angle=angle%360; if(angle<0) angle+=360; double temp; temp=COS[angle]*x-SIN[angle]*y; y=SIN[angle]*x+COS[angle]*y; x=temp; } }; int len[10005],a[10005]; const int maxn=2<<15; int size,temp; Node node[maxn]; void build(int n) { n+=2; size=1; while(size<n) size<<=1; memset(node,0,sizeof(node)); } void build(int n,int a[]) { int i,h=1,m; build(n); for(i=1; i<=n; i++) { node[i+size].y=a[i]; } m=n+size; for(i=size-1; i>0; i--) { if(i<<h<=m) { if(i<<h==size) h++; node[i].x=node[i+i].x+node[i+i+1].x; node[i].y=node[i+i].y+node[i+i+1].y; } } node[0].angle=0; } void putdown(int s,int t)///将标记放下 { if(s^1) { putdown(s>>1,t>>1); } if(node[s].angle) { node[s<<1].angle+=node[s].angle; node[s<<1^1].angle+=node[s].angle; node[s].angle=0; } if(node[t].angle) { node[t<<1].angle+=node[t].angle; node[t<<1^1].angle+=node[t].angle; node[t].angle=0; } } void inline update(int pos) { temp=pos<<1; if(pos<size) { node[pos].x=node[temp].x+node[temp^1].x; node[pos].y=node[temp].y+node[temp^1].y; } else { node[pos].x=0; node[pos].y=len[pos-size]; } if(node[pos].angle) node[pos].rotate(); } void add(int l,int n,int angle)///更新 { int s=l+size,t=n+size+1; putdown(s>>1,t>>1); for(; s^t^1; s>>=1,t>>=1) { if(~s&1) { node[s^1].angle+=angle; } update(s); update(s^1); if(t&1) { node[t^1].angle+=angle; } update(t); update(t^1); } update(s); update(t); while(s>1) { update(s>>=1); } } inline void Out(int a) //输出外挂 { if(a>9) Out(a/10); putchar(a%10+'0'); } int tmp; void write(double a) { if(a<0) { putchar('-'); a=-a; } Out((int)a); putchar('.'); tmp=(a-int(a))*100; putchar(tmp/10+'0'); putchar(tmp%10+'0'); } inline void Read(int &x) { x=0; char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } } int main() { int i,j,n,m,x,y,d,t=1,cas=0,angle; double arc; for(i=0; i<360; i++) { arc=(double)i*PI/180; SIN[i]=sin(arc); COS[i]=cos(arc); } while(scanf("%d",&n)!=EOF) { Read(m); if(cas) { puts(""); } cas++; memset(len,0,sizeof(len)); for(i=1; i<=n; i++) { // scanf("%d",&len[i]); Read(len[i]); a[i]=180; } build(n,len); while(m--) { Read(x); Read(angle); add(x,n,angle-a[x]); a[x]=angle; write(node[1].x); putchar(' '); write(node[1].y); putchar('\n'); } } return 0; }