2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!!
官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解)
A. 树链剖分数据结构板题
题目大意:我没看,看不懂。
基本思路:我不会。
参考代码:找Oyk老师和Czj老师去。
B. The background of water problem
题目大意(大写加粗的水题):给定$N$个学生和他们$K$个科目的成绩$S_i$,再给出各科目$K_i$的权重顺序$Q_i$,求排名之后,拥有id为$X$的是哪个学生。
基本思路:虽然$K$只有$10$,$S$只有$100$,但有M组查询,所以当然不能开个long long去hash每个学生。我们简单点,开个结构体,排个序,就好了。
参考代码:
官方代码(将成绩和id分开放,避免在排序时复制构造大结构体):
1 #include <cstdio> 2 #include <string.h> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 int N,K,M,X; 8 int people[1005][11]; 9 int cmpOrder[11]; 10 11 struct CmpNode{ 12 CmpNode(int x):id(x){} 13 int id; 14 bool operator < (const CmpNode &other) const 15 { 16 for(int i=0; i<K; i++) 17 { 18 if(people[this->id][cmpOrder[i]] > people[other.id][cmpOrder[i]]) 19 return true; 20 else if(people[this->id][cmpOrder[i]] < people[other.id][cmpOrder[i]]) 21 return false; 22 } 23 return this->id<other.id; 24 } 25 }; 26 27 void solve(FILE *fin=stdin, FILE *fout=stdout) 28 { 29 int t; 30 fscanf(fin,"%d",&t); 31 while(t--) 32 { 33 fscanf(fin,"%d%d",&N,&K); 34 vector<CmpNode> nodes; 35 for(int i=0;i<N;i++) 36 { 37 nodes.push_back(CmpNode(i)); 38 for(int j=1;j<=K;j++) 39 fscanf(fin,"%d",&people[i][j]); 40 } 41 fscanf(fin,"%d",&M); 42 while(M--) 43 { 44 for(int i=0;i<K;i++) 45 fscanf(fin,"%d",cmpOrder+i); 46 fscanf(fin,"%d", &X); 47 sort(nodes.begin(),nodes.end()); 48 fprintf(fout,"%d\n",nodes[X-1].id+1); 49 } 50 } 51 } 52 53 int main() 54 { 55 solve(stdin,stdout); 56 return 0; 57 }
非官方代码(这是通通放在结构体的例子,无论算法竞赛还是工程都不建议这么排序):
1 #include <stdio.h> 2 #include <algorithm> 3 4 int N, K, M, X; 5 int order[11]; 6 7 struct stu { 8 int id, score[11]; 9 bool operator <(const stu&x) const { 10 for(int i=1; i<=K; i++) 11 if(score[order[i]] != x.score[order[i]]) 12 return score[order[i]] > x.score[order[i]]; 13 return id < x.id; 14 } 15 }student[1001]; 16 17 int main() { 18 int T; 19 scanf("%d", &T); 20 while(T--) { 21 scanf("%d%d", &N, &K); 22 for(int i=1; i<=N; i++) { 23 student[i].id = i; 24 for(int j=1; j<=K; j++) 25 scanf("%d", &student[i].score[j]); 26 } 27 scanf("%d", &M); 28 while(M--) { 29 for(int i=1; i<=K; i++) 30 scanf("%d", order+i); 31 std::sort(student+1, student+1+N); 32 scanf("%d", &X); 33 printf("%d\n", student[X].id); 34 } 35 } 36 return 0; 37 }
C. Oyk cut paper forever
题目大意:
永远的Oyk剪纸(大雾)。Oyk给面子Z大师,玩$C$轮剪纸,每轮给定一条长为$k$个单位的纸带,Z大师先手可以剪去(任意)$N_1$个单位,但不能不剪或全部拿走。此后每轮都只能剪$1$到$2\times N_1$个单位,能拿走最后一段纸带的人获胜,问Oyk第一次获胜是第几轮。
基本思路:
斐波那契博弈,证明参见:
原题参见 hdoj 2516. 取石子游戏 等。
首先知道了这是个斐波那契博弈,接下来我们要做的就是判断$K_i$是否为Fibonacci数。容易想到的是用递推打一个表,将Fibonacci数存起来或标记一下。但是我们知道斐波那契数列通项公式为$F_n=\frac1{\sqrt5}\left[\left(\frac{1+\sqrt5}2\right)^n-\left(\frac{1-\sqrt5}2\right)^n\right]$(比内公式),还知道判断一个数$x$是否为Fibonacci数只需判断$5x^2+4$或$5x^2-4$是否为完全平方数(参考:Wiki,示例)(即判断开根号后是否为整数),于是Over。
参考代码:
官方代码(丧sha病bi出题人改了好几波代码,我们还是假装下面的是对的吧):
1 #include <cstdlib> 2 #include <cstdio> 3 #include <cmath> 4 using namespace std; 5 6 int main() 7 { 8 int T; 9 scanf("%d",&T); 10 while(T--){ 11 int n,i; 12 int ans=0; 13 scanf("%d",&n); 14 for(i = 1;i<=n;i++){ 15 int a; 16 scanf("%d",&a); 17 if(!ans&&(sqrt(5*a*a+4)-(int)sqrt(5*a*a+4)<1e-6||sqrt(5*a*a-4)-(int)sqrt(5*a*a-4)<1e-6)){ 18 ans=i; 19 } 20 } 21 if(ans)printf("%d\n",ans); 22 else puts("Oyk forever!"); 23 } 24 return 0; 25 }
非官方代码(打表出奇迹):
1 #include <stdio.h> 2 using namespace std; 3 4 int flag[100100]; 5 void init() { 6 int a = 1, b = 2; 7 while(b<=100000) { 8 ++flag[b]; 9 b += a; 10 a = b-a; 11 } 12 } 13 int main() { 14 int T; init(); 15 scanf("%d", &T); 16 while(T--) { 17 int C, k, res=0; 18 scanf("%d", &C); 19 for(int i=1; i<=C; i++) { 20 scanf("%d", &k); 21 if(!res&&flag[k]) 22 res = i; 23 } 24 res?printf("%d\n", res):puts("Oyk forever!"); 25 } 26 return 0; 27 }
D. 最小费用流
题目大意:
挖$n$天的宝藏,每天需要$R_i$只铲子,当天用完会坏掉。有$3$种方式准备铲子:从商店买,$p$元一只;找铁匠$A$修理,每只$f$元同时修$m$天;找铁匠$B$修理,每只$s$元同时修$t$天。问最小花费。
基本思路:
最小费用流,参见网络流24题之餐巾问题。
参考代码:
1 #include <iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #define INF 99999999 5 #define min(x,y) (x)>(y)?(y):(x) 6 #define abs(x) ((x)>0?(x):-(x)) 7 #define E 50000 8 struct p 9 { 10 int v,next,k,t,cost; 11 }edge[200000]; 12 int n,m,ans,tot,S,T,head[1001],pre[1001],pid[1001],pop[100001]; 13 int mark[1001],dis[1001],now[1001]; 14 void addedge(int a,int b,int k,int cost) 15 { 16 edge[tot].v=b; 17 edge[tot].k=k; 18 edge[tot].cost=cost; 19 edge[tot].t=tot+1; 20 edge[tot].next=head[a]; 21 head[a]=tot++; 22 23 edge[tot].v=a; 24 edge[tot].k=0; 25 edge[tot].cost=-cost; 26 edge[tot].t=tot-1; 27 edge[tot].next=head[b]; 28 head[b]=tot++; 29 } 30 int spfa() 31 { 32 int i,top,tail,cur; 33 for(i=0;i<=T;i++) 34 dis[i]=INF,mark[i]=0; 35 top=tail=0; 36 pop[top++]=S; 37 dis[S]=0; 38 mark[S]=1; 39 while(tail!=top) 40 { 41 cur=pop[tail++]; 42 tail%=50000; 43 mark[cur]=0; 44 for(i=head[cur];i!=-1;i=edge[i].next) 45 if(edge[i].k>0&&dis[edge[i].v]>dis[cur]+edge[i].cost) 46 { 47 dis[edge[i].v]=dis[cur]+edge[i].cost; 48 pre[edge[i].v]=cur; 49 pid[edge[i].v]=i; 50 if(mark[edge[i].v]==0) 51 { 52 mark[edge[i].v]=1; 53 pop[top++]=edge[i].v; 54 top%=50000; 55 } 56 } 57 } 58 return dis[T]; 59 } 60 int mincost() 61 { 62 int i,flow,tmp,ans,maxflow=0; 63 ans=0; 64 while(1) 65 { 66 tmp=spfa(); 67 if(tmp==INF) break; 68 flow=INF; 69 for(i=T;i!=S;i=pre[i]) 70 if(edge[pid[i]].k<flow) 71 flow=edge[pid[i]].k; 72 for(i=T;i!=S;i=pre[i]) 73 { 74 edge[pid[i]].k-=flow; 75 edge[edge[pid[i]].t].k+=flow; 76 } 77 maxflow+=flow; 78 ans+=tmp*flow; 79 } 80 return ans; 81 } 82 int main() 83 { 84 freopen("in.txt","r",stdin); 85 freopen("out.txt","w",stdout); 86 int i,j,p,m1,f,m2,s,tmp; 87 while(scanf("%d%d%d%d%d%d",&n,&p,&m1,&f,&m2,&s)!=EOF) 88 { 89 memset(edge,0xff,sizeof(edge)); 90 tot=n*2+3; 91 S=0; 92 T=n*2+1; 93 for(i=1;i<=n;i++) 94 { 95 scanf("%d",&tmp); 96 tmp++; 97 addedge(S,i+n,INF,p); 98 addedge(S,i,tmp,0); 99 addedge(i+n,T,tmp,0); 100 if(i<n) addedge(i,i+1,INF,0); 101 if(i+m1<=n) addedge(i,n+i+m1,INF,f); 102 if(i+m2<=n) addedge(i,n+i+m2,INF,s); 103 } 104 printf("%d\n",mincost()); 105 } 106 return 0; 107 }
E. Wwj's work
题目大意:这题是HDOJ 4622. Reincarnation原题,有且仅有数据是自己造的。。
基本思路:求一个字符串的子串数目,标准的后缀自动机。当然似乎也可以后缀数组、后缀xxx什么的乱搞。
参考代码:(参考kuangbin的模板,和代码)
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 const int CHAR = 26; 7 const int MAXN = 2020; 8 struct SAM_Node { 9 SAM_Node *fa, *next[CHAR]; 10 int len; 11 int id,pos; 12 SAM_Node() {} 13 SAM_Node(int _len) { 14 fa = 0; 15 len = _len; 16 memset(next,0,sizeof(next)); 17 } 18 }; 19 SAM_Node SAM_node[MAXN*2], *SAM_root, *SAM_last; 20 int SAM_size; 21 SAM_Node *newSAM_Node(int len) { 22 SAM_node[SAM_size] = SAM_Node(len); 23 SAM_node[SAM_size].id = SAM_size; 24 return &SAM_node[SAM_size++]; 25 } 26 SAM_Node *newSAM_Node(SAM_Node *p) { 27 SAM_node[SAM_size] = *p; 28 SAM_node[SAM_size].id = SAM_size; 29 return &SAM_node[SAM_size++]; 30 } 31 void SAM_init() { 32 SAM_size = 0; 33 SAM_root = SAM_last = newSAM_Node(0); 34 SAM_node[0].pos = 0; 35 } 36 void SAM_add(int x,int len) { 37 SAM_Node *p = SAM_last, *np = newSAM_Node(p->len+1); 38 np->pos = len; 39 SAM_last = np; 40 for(; p && !p->next[x]; p = p->fa) 41 p->next[x] = np; 42 if(!p) { 43 np->fa = SAM_root; 44 return; 45 } 46 SAM_Node *q = p->next[x]; 47 if(q->len == p->len + 1) { 48 np->fa = q; 49 return; 50 } 51 SAM_Node *nq = newSAM_Node(q); 52 nq->len = p->len + 1; 53 q->fa = nq; 54 np->fa = nq; 55 for(; p && p->next[x] == q; p = p->fa) 56 p->next[x] = nq; 57 } 58 59 int sub[MAXN][MAXN]; 60 char S[MAXN]; 61 void read() { 62 memset(sub, 0, sizeof(sub)); 63 scanf("%s", S); 64 int len = strlen(S); 65 for(int i=0; i<len; i++) { 66 SAM_init(); 67 for(int j=i; j<len; j++) 68 SAM_add(S[j]-'a', j-i+1); 69 for(int j=1; j<SAM_size; j++) 70 sub[i][ SAM_node[j].pos+i-1 ] 71 += SAM_node[j].len - SAM_node[j].fa->len; 72 for(int j=i+1; j<len; j++) 73 sub[i][j] += sub[i][j-1]; 74 } 75 } 76 void work() { 77 int Q, l, r; 78 scanf("%d", &Q); 79 while(Q--) { 80 scanf("%d%d", &l, &r); 81 printf("%d\n", sub[l-1][r-1]); 82 } 83 } 84 int main() { 85 int T; 86 scanf("%d", &T); 87 while(T--) { 88 read(); 89 work(); 90 } 91 return 0; 92 }
F. 防AK题,dfs+高斯消元
题目大意:我没看,看不懂。
基本思路:我不会。
参考代码:找Czj去。
G. Not Easy Math Problem
题目大意:$F(m,n)=\left\{\begin{matrix}\begin{aligned}&B*2^{m-1},&n=0\\&\sum_{i=1}^m F(i, n-1),&n>0\end{aligned}\end{matrix}\right.$,其中$m<10^6$,$n<10^3$,$B<10$,求$F(m,n)\%(1E8+7)$。
基本思路:
递推法:
先观察前面若干行若干列,发现各项系数构成杨辉三角。代几个数进去发现 $\displaystyle F(m,n)=B*\sum_{i=0}^{m-1}C_{m-i+n-2}^{n-1}*2^i$。
$O(M)$肯定会TLE啊,算算算 $\displaystyle \frac{2F(m,n)-F(m,n)}{B}=C_{n-1}^{n-1}*2^m-C_{m+n-2}^{n-1}*2^0+\sum_{i=1}^{m-1}\left(C_{m-i+n-1}^{n-1}-C_{m-i+n-2}^{n-1}\right)*2^i$
发现可以利用组合数性质,令$\displaystyle T(n-1)=\sum_{i=0}^{m-1}C_{m-i+n-2}^{n-1}*2^i$,$\displaystyle T(n-2)=\sum_{i=0}^{m-1}C_{m-i+n-2}^{n-2}*2^i$
则$\displaystyle T(n-1)=C_{n-1}^{n-1}*2^m-C_{m+n-2}^{n-1}+T(n-2)-C_{m+n-2}^{n-2}$
递推下去得$\displaystyle T(n-1)=2^{n-1}*2^m-2*\sum_{i=0}^{n-2}C_{m+n-2}^i-C_{m+n-2}^{n-1}$
来个快速幂,再预处理下逆元和组合数,$O(log(M+N)+N)$跑得飞快($log$里面的$N$可以在前面预处理组合数的循环去掉,丑就是了)。
数学归纳法:
参见 hdoj. 5490 题解。归纳公式为$\displaystyle F(m,n)=\frac{q*F(m,n-1)-B*C_{m+n-2}^{n-1}}{q-1}$,然后递推,时间复杂度$O(log(M)+N)$(如果用快速幂算$2^{m-1}$的话)。
参考代码(我的一定比标算好看):
1 #include <stdio.h> 2 const int MOD = 100000007; 3 inline int add(int a, int b) { return (a%MOD+b%MOD)%MOD; } 4 inline int sub(int a, int b) { return ((a-b)%MOD+MOD)%MOD; } 5 inline int mul(int a, int b) { return int((long long)a%MOD*(b%MOD)%MOD); } 6 inline int pow(int x, int n) { 7 int res = 1; 8 while(n) { 9 if(n&1) res = mul(res, x); 10 x = mul(x, x); 11 n >>= 1; 12 } 13 return res; 14 } 15 int inv[1001]={1,1}; 16 void init() { 17 for(int i=2; i<=1000; i++) 18 inv[i] = mul(inv[MOD%i], MOD-MOD/i); 19 } 20 int B, M, N; 21 void read() { 22 scanf("%d%d%d", &B, &M, &N); 23 } 24 int Binomial[1001]={1}; 25 void work() { 26 for(int i=1; i<N; i++) 27 Binomial[i] = mul(mul(Binomial[i-1], M+N-i-1), inv[i]); 28 int res = pow(2, M+N-1); 29 for(int i=0; i<N; i++) 30 res = sub(res, mul(Binomial[i], 2)); 31 res = mul(add(res, Binomial[N-1]), B); 32 printf("%d\n", res); 33 } 34 int main() { 35 int T; init(); 36 scanf("%d", &T); 37 while(T--) { 38 read(); 39 work(); 40 } 41 return 0; 42 }
H. Party!
题目大意:
Wwj和他的女朋友们总共$N$个人去开趴体。每个人如果还没把自己的礼物送出去的话,就可以从别人手中收到礼物。第$i$个人得到第$j$人礼物的同时,也会得到一个快乐指数$H_{i,\ j}$。求所有人的快乐指数的总和的最大值。
基本思路:
诶?有人用贪心做?有人用搜索做?听说还有人用最小生成树做?诶等等那个用无向图MST的什么心态?这不是有向图?(我的天呐.jpg)
这题可以跑一个网络流,当然也可以DP。谁告诉你给一个矩阵就一定是图论题了?mdzz。
能DP我当然不写网络流,考虑收礼物状态矩阵$M$,$M_{i,\ j}$代表第$i$个人收没收第$j$人的礼物($i\neq j$),收了为$1$,没收为$0$。由于每个人只有一份礼物,他只能送给一个人,所以在同一列内最多只有$1$个$1$,所以状态矩阵$M$可以直接拍扁。好的,$N\leq 10$,我们可以愉快地状态压缩了,状态数$2^N-1$,dp时间复杂度$O(2^N N^2)$。
考虑任意状态state,如果第$i\geq 0$位为$1$(即$state\&(1<<i)!=0$),则表明该状态下第$i$个人已经把他的礼物给出去了(当然也不可能发生给自己的情况)。对每一个状态求最大快乐指数,再取所有状态的最大值。
参考代码:
1 #include <stdio.h> 2 3 int N, H[11][11]; 4 inline void getMax(int&n, int x) { if(n<x) n=x; } 5 void read() { 6 scanf("%d", &N); 7 for(int i=0; i<N; i++) 8 for(int j=0; j<N; j++) 9 scanf("%d", H[i]+j); 10 } 11 void work() { 12 int maxState = 1<<N, dp[maxState]={0}; 13 for(int state=0; state<maxState; state++) 14 for(int i=0; i<N; i++) if(!(state&(1<<i))) 15 for(int j=0; j<N; j++) if(i!=j&&!(state&(1<<j))) 16 getMax(dp[state+(1<<j)], dp[state]+H[i][j]); 17 int res = 0; 18 for(int state=0; state<maxState; state++) 19 getMax(res, dp[state]); 20 printf("%d\n", res); 21 } 22 int main() { 23 int T; 24 scanf("%d",&T); 25 while(T--) { 26 read(); 27 work(); 28 } 29 return 0; 30 }
I. Square
题目大意:$N\times N$的矩阵,每个格子要填$0$或$1$,要求每行每列中$1$的个数要是奇数个。
基本思路:不考虑限制条件,有$2^{N^2}$种方案对吧?能乱填对吧?那如何保证每行每列中$1$的个数是奇数个?在旁边加多一行加多一列(即$(N+1)\times(N+1)$),对于每一行每一列,如果$1$的个数是偶数个,再填个$1$,否则填$0$进去。啥?剩下那个格子怎么办?会一边奇数一边偶数?嗯,由于是$N\times N$,所以是不可能的。因此$S_N=2^{(N-1)^2}$,快速幂或者奇怪的优化即可。
参考代码:
官方代码(分块处理,把47改成15,不用long long用int也是可以的,当然时间就差个2.5倍咯):
1 #include <stdio.h> 2 #define ULL unsigned long long 3 int main() { 4 ULL res; 5 int n; 6 int T; 7 scanf("%d",&T); 8 while(T--) { 9 scanf("%d",&n); 10 res=1; 11 for(ULL i = 0; i<(ULL)(n-1)*(n-1)/47; i++) 12 res=(res<<47)%100007; 13 for(ULL i = 0; i<(ULL)(n-1)*(n-1)%47; i++) 14 res=(res*2)%100007; 15 printf("%d\n",res); 16 } 17 return 0; 18 }
非官方代码(快速幂,怎么说也是log的复杂度,比上面奇怪的优化要快就是了):
1 #include <stdio.h> 2 const int MOD = 100007; 3 long long pow(long long x, int n) { 4 long long res = 1LL; 5 while(n) { 6 if(n&1) res = res*x%MOD; 7 x = x*x%MOD; 8 n >>= 1; 9 } 10 return res; 11 } 12 int main() { 13 int T, N; 14 scanf("%d",&T); 15 while(T--) { 16 scanf("%d",&N); 17 --N; N *= N; 18 printf("%d\n", pow(2, N)); 19 } 20 return 0; 21 }
J. Rotate and skew
题目大意:
windows系统里面有个“画图”工具,相信大家一定不会陌生。但里面没有旋转任意$x$角度的功能,只有“扭曲”的功能。如逆时针旋转$28^\circ$,我们发现可以先对$x$轴扭曲$-14^\circ$,再对$y$轴扭曲$25^\circ$,再对$x$轴扭曲$-14^\circ$,就成功辣!问给定角度$x$,输出三次扭曲的角度。
基本思路:
好多同学可能一开始先取个基向量,比如$\vec b=(0,1)$,然后想$x$轴扭曲$-14^\circ$应该是$\vec{b'}=(tan14^\circ,1)$,$y$轴再扭曲$25^\circ$应该是$\vec{b''}=(tan14^\circ, 1-tan25^\circ)$,再扭曲一下……再$arc tan$一下……咦?怎么出来的不是$28^\circ$了?
Naive。如果是这样那还叫扭曲吗?那叫拉伸!你倒是把$x$乘进去啊!把$y$乘进去啊!
- 首先考虑基向量$\vec a=(1,0)$。设旋转角度$\theta$。先水平扭曲任意角度,不变。垂直扭曲$\varphi$,$\vec{a'}=(1, tan\varphi)$,再水平扭曲一次得$\vec{a''}=(1-tan(x), tan\varphi)$,和$tan\theta$解一下发现$x=\frac\theta2$,于是知道了水平扭曲角度。
- 正解(1):考虑向量$\vec x=\begin{bmatrix}x\\y\end{bmatrix}$,水平扭曲矩阵$A=\begin{bmatrix}1&tan(-\frac\theta2)\\0&1\end{bmatrix}$, ($A\vec x=\begin{bmatrix}x+ytan(-\frac\theta2)\\y\end{bmatrix}$,看不懂的学线代去)
- 三个扭曲矩阵相乘应该是$M=ABA$,其中我们要求的是中间的垂直扭曲矩阵$B$。
- 已知旋转矩阵$M=\begin{bmatrix}cos\theta&-sin\theta\\sin\theta&cos\theta\end{bmatrix}$,解得$B=\begin{bmatrix}1&0\\sin\theta&1\end{bmatrix}$。
- 但是我们的垂直扭曲矩阵应该要长成$B=\begin{bmatrix}1&0\\tan\varphi&1\end{bmatrix}$的样子。
- 所以我们需要用$tan$正切值去模拟$sin$正弦值(本来就是要求用扭曲模拟旋转)。
- 正解(2):再考虑基向量$\vec b=(0,1)$。
- 联立化简 $\left\{\begin{matrix}\begin{aligned}&x_1=x_0+y_0*tan(-\frac\theta2)\\&y_1=y_0+x_1*tan(\varphi)\\&x_2=x_1+y_1*tan(-\frac\theta2)\end{aligned}\end{matrix}\right.$,$\left\{\begin{matrix}\begin{aligned}&x_0=0,\ y_0=1\\&tan(-\theta)=\frac{x_2}{y_1}\end{aligned}\end{matrix}\right.$ 得 $\displaystyle\frac{tan(\frac\theta2)[sec(\theta)tan(\varphi)-tan(\theta)]}{tan(\frac\theta2)tan(\varphi)-1}=0$
- 解 $sec(\theta)tan(\varphi)=tan(\theta)$ 得垂直扭曲角度 $\varphi=tan^{-1}sin(\theta)$
- 啥?你还要$+k\pi$?你还要分母不为$0$?$\theta$不为$0$?这都要我解,你咋不上天呢。
- 发现题目对精度要求不高,反正切取个整即可。也可以直接打个垂直扭曲角度的表。
- 更多请参考 Matrix67—线性代数的妙用:怎样在Windows画图软件中实现28度旋转?
参考代码:
对基向量$\vec b=(0,1)$的模拟:
1 #include <stdio.h> 2 #include <math.h> 3 const double PI = acos(-1.L); 4 int main() { 5 double x = 0.0, y = 1.0; 6 x = x + tan(-14.*PI/180.) * y; 7 y = y + tan(25.*PI/180.) * x;///注意这里是tan25模拟sin28,若这里直接用sin28则最后atan回来的结果是28.0整 8 x = x + tan(-14.*PI/180.) * y; 9 printf("%f\n", atan(x/y)*180./PI); 10 return 0; 11 }
官方代码:
1 // http://scarky.com/widget/getiframe/PLNRB5QG/ 2 #include <stdio.h> 3 int y[]={0,2,4,6,8,10,12,14,15,17,19,21,22,24,25,27,28,29,30,32,33,34,35}; 4 int main(int i) { 5 while(~scanf("%d", &i)) 6 i/=2, printf("%d %d %d\n", -i, i>0?y[i]:-y[-i], -i); 7 return 0; 8 }
非官方代码:
1 #include <stdio.h> 2 #include <math.h> 3 const double PI = acos(-1.L); 4 int main() { 5 int x; 6 while(~scanf("%d", &x)) 7 printf("%d %.f %d\n", -x/2, round(atan(sin(x*PI/180.))*180./PI), -x/2); 8 return 0; 9 }