zoukankan      html  css  js  c++  java
  • 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
    ",nodes[X-1].id+1);
    49         }
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     solve(stdin,stdout);
    56     return 0;
    57 }
    B. The background of water problem

    非官方代码(这是通通放在结构体的例子,无论算法竞赛还是工程都不建议这么排序):

     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
    ", student[X].id);
    34         }
    35     }
    36     return 0;
    37 }
    B. The background of water problem 

    C. Oyk cut paper forever

    题目大意

      永远的Oyk剪纸(大雾)。Oyk给面子Z大师,玩$C$轮剪纸,每轮给定一条长为$k$个单位的纸带,Z大师先手可以剪去(任意)$N_1$个单位,但不能不剪或全部拿走。此后每轮都只能剪$1$到$2 imes N_1$个单位,能拿走最后一段纸带的人获胜,问Oyk第一次获胜是第几轮。

    基本思路

      斐波那契博弈,证明参见:

      原题参见 hdoj 2516. 取石子游戏 等。

      首先知道了这是个斐波那契博弈,接下来我们要做的就是判断$K_i$是否为Fibonacci数。容易想到的是用递推打一个表,将Fibonacci数存起来或标记一下。但是我们知道斐波那契数列通项公式为$F_n=frac1{sqrt5}left[left(frac{1+sqrt5}2 ight)^n-left(frac{1-sqrt5}2 ight)^n ight]$(比内公式),还知道判断一个数$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
    ",ans);
    22         else puts("Oyk forever!");
    23     }
    24     return 0;
    25 }
    C. OykOyk!

    非官方代码(打表出奇迹):

     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
    ", res):puts("Oyk forever!");
    25     }
    26     return 0;
    27 }
    C. Oyk forever!

     

    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
    ",mincost());
    105     }
    106     return 0;
    107 }
    D. Dig the treasure

    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
    ", 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 }
    E. Wwj's work

    F. 防AK题,dfs+高斯消元

    题目大意:我没看,看不懂。

    基本思路:我不会。

    参考代码:找Czj去。

    G. Not Easy Math Problem

    题目大意:$F(m,n)=left{egin{matrix}egin{aligned}&B*2^{m-1},&n=0\&sum_{i=1}^m F(i, n-1),&n>0end{aligned}end{matrix} ight.$,其中$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} ight)*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
    ", 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 }
    比标算好看一丢丢的 G.

    H. Party!

    题目大意

      Wwj和他的女朋友们总共$N$个人去开趴体。每个人如果还没把自己的礼物送出去的话,就可以从别人手中收到礼物。第$i$个人得到第$j$人礼物的同时,也会得到一个快乐指数$H_{i, j}$。求所有人的快乐指数的总和的最大值。

    基本思路

      诶?有人用贪心做?有人用搜索做?听说还有人用最小生成树做?诶等等那个用无向图MST的什么心态?这不是有向图?(我的天呐.jpg)

      这题可以跑一个网络流,当然也可以DP。谁告诉你给一个矩阵就一定是图论题了?mdzz。

      能DP我当然不写网络流,考虑收礼物状态矩阵$M$,$M_{i, j}$代表第$i$个人收没收第$j$人的礼物($i eq j$),收了为$1$,没收为$0$。由于每个人只有一份礼物,他只能送给一个人,所以在同一列内最多只有$1$个$1$,所以状态矩阵$M$可以直接拍扁。好的,$Nleq 10$,我们可以愉快地状态压缩了,状态数$2^N-1$,dp时间复杂度$O(2^N N^2)$。

      考虑任意状态state,如果第$igeq 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
    ", res);
    21 }
    22 int main() {
    23     int T;
    24     scanf("%d",&T);
    25     while(T--) {
    26         read();
    27         work();
    28     }
    29     return 0;
    30 }
    H. Party!

    I. Square

    题目大意:$N imes N$的矩阵,每个格子要填$0$或$1$,要求每行每列中$1$的个数要是奇数个。

    基本思路:不考虑限制条件,有$2^{N^2}$种方案对吧?能乱填对吧?那如何保证每行每列中$1$的个数是奇数个?在旁边加多一行加多一列(即$(N+1) imes(N+1)$),对于每一行每一列,如果$1$的个数是偶数个,再填个$1$,否则填$0$进去。啥?剩下那个格子怎么办?会一边奇数一边偶数?嗯,由于是$N imes 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
    ",res);
    16     }
    17     return 0;
    18 }
    I. Square

    非官方代码(快速幂,怎么说也是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
    ", pow(2, N));
    19     }
    20     return 0;
    21 }
    I. Square

    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)$。设旋转角度$ heta$。先水平扭曲任意角度,不变。垂直扭曲$varphi$,$vec{a'}=(1, tanvarphi)$,再水平扭曲一次得$vec{a''}=(1-tan(x), tanvarphi)$,和$tan heta$解一下发现$x=frac heta2$,于是知道了水平扭曲角度。
    • 正解(1):考虑向量$vec x=egin{bmatrix}x\yend{bmatrix}$,水平扭曲矩阵$A=egin{bmatrix}1&tan(-frac heta2)\0&1end{bmatrix}$, ($Avec x=egin{bmatrix}x+ytan(-frac heta2)\yend{bmatrix}$,看不懂的学线代去)
      • 三个扭曲矩阵相乘应该是$M=ABA$,其中我们要求的是中间的垂直扭曲矩阵$B$。
      • 已知旋转矩阵$M=egin{bmatrix}cos heta&-sin heta\sin heta&cos hetaend{bmatrix}$,解得$B=egin{bmatrix}1&0\sin heta&1end{bmatrix}$。
      • 但是我们的垂直扭曲矩阵应该要长成$B=egin{bmatrix}1&0\tanvarphi&1end{bmatrix}$的样子。
      • 所以我们需要用$tan$正切值去模拟$sin$正弦值(本来就是要求用扭曲模拟旋转)。
    • 正解(2):再考虑基向量$vec b=(0,1)$。
      • 联立化简 $left{egin{matrix}egin{aligned}&x_1=x_0+y_0*tan(-frac heta2)\&y_1=y_0+x_1*tan(varphi)\&x_2=x_1+y_1*tan(-frac heta2)end{aligned}end{matrix} ight.$,$left{egin{matrix}egin{aligned}&x_0=0, y_0=1\&tan(- heta)=frac{x_2}{y_1}end{aligned}end{matrix} ight.$  得  $displaystylefrac{tan(frac heta2)[sec( heta)tan(varphi)-tan( heta)]}{tan(frac heta2)tan(varphi)-1}=0$
      • 解 $sec( heta)tan(varphi)=tan( heta)$ 得垂直扭曲角度 $varphi=tan^{-1}sin( heta)$
      • 啥?你还要$+kpi$?你还要分母不为$0$?$ heta$不为$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
    ", 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
    ", -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
    ", -x/2, round(atan(sin(x*PI/180.))*180./PI), -x/2);
    8     return 0;
    9 }

    ——原创by BlackStorm,转载请注明出处。

    本文地址:http://www.cnblogs.com/BlackStorm/p/5380872.html

  • 相关阅读:
    什么是桌面虚拟化,实施桌面虚拟化有什么好处?[转]
    运维工程师的职责和前景
    informix 中chunk/dbspace概念
    让用户体验决定桌面虚拟化成败
    专访运维与人才外包专家黄琨:运维工作最大的挑战是什么?
    PD与DBMS中的数据类型
    informix长事务的处理方式
    Oracle expdp/impdp导出导入命令及数据库备份(转)
    wpf的treeview显示item时候不能stretch的一个解决办法
    Jenkins 用户权限管理
  • 原文地址:https://www.cnblogs.com/BlackStorm/p/5380872.html
Copyright © 2011-2022 走看看