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 }
A题代码

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 }
B题代码

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 }
C题解代码

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 }
D题代码

 

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;
}
E题代码

再丧心病狂加了一堆优化后,加外输入输出优化

用时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;
}
优化后的代码

 



posted @ 2017-02-16 09:32  强势围观  阅读(241)  评论(0编辑  收藏  举报