360春招笔试算法题题解

来源:互联网 发布:淘宝卖家钱怎么到账 编辑:程序博客网 时间:2024/05/15 09:07

赛码网地址

360春招笔试算法题题解

A. 跑步(水)

题目描述

小明同学喜欢体育锻炼,他常常去操场上跑步。跑道是一个圆形,在本题中,我们认为跑道是一个半径为R的圆形,设圆心的坐标为原点(0,0)。 
小明跑步的起点坐标为(R,0),他沿着圆形跑道跑步,而且一直沿着一个方向跑步。回到家后,他查看了自己的计步器,计步器显示他跑步的总路程为L。 
小明想知道自己结束跑步时的坐标,但是他忘记自己是沿着顺时针方向还是逆时针方向跑的了。他想知道在这两种情况下的答案分别是多少。

题目解析:

我们都知道,L=Rθ,那么求出 θ来,x=rcosθ,y=rsinθ就好了。再把y反过来

#include <bits/stdc++.h>using namespace std;#define RE(x) freopen(x,"r",stdin)#define WR(x) freopen(x,"w",stdout)#define INF 0x3f3f3f3f#define CLEAR(x) memset(x,0,sizeof(x))#define pb push_back#define mp make_pairtypedef long long ll;typedef vector<int> vi;typedef vector<ll> vl;typedef pair<int,int> pii;const int M = 1e9+7;const double PI = acos(-1.0);const double eps = 1e-8;int main() {    //RE("in.txt");WR("out.txt");    int l,r;    cin>>l>>r;    double theta = l*1.0/r;    double x=r*cos(theta),y=r*sin(theta);    printf("%.3lf %.3lf\n%.3lf %.3lf\n",x,-y,x,y);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

B. 剪气球串(状压DP)

题目描述

小明买了一些彩色的气球用绳子串在一条线上,想要装饰房间,每个气球都染上了一种颜色,每个气球的形状都是各不相同的。我们用1到9一共9个数字表示不同的颜色,如12345则表示一串5个颜色各不相同的气球串。但小明希望得到不出现重复颜色的气球串,那么现在小明需要将这个气球串剪成多个较短的气球串,小明一共有多少种剪法?如原气球串12345的一种是剪法是剪成12和345两个气球串。 
注意每种剪法需满足最后的子串中气球颜色各不相同(如果满足该条件,允许不剪,即保留原串)。两种剪法不同当且仅当存在一个位置,在一种剪法里剪开了,而在另一种中没剪开。详见样例分析。

题目解析

其实这题的意思就是,把一个数组切成若干子数组,要求每一段里面都没有重复数字,问有多少切法。

观察到一共就9种数字,且第i个数字只与最后一段有关系,考虑 状压dp。令dp[i][s]表示前i个数,最后一串的状态为s的切法。那么,最终答案可表示为: 

s=1512dp[n][s]

然后在推第i个球时考虑两种情况,一是这个球自己成为一段(这时候是无条件的),二是这个球和前面一段绑在一起(要求第i个球与前面一段没有重复颜色),由此写出转移方程: 
dp[i][1<<(a[i]1)]=s=1512dp[i1][s]

dp[i][s|j]=dp[i1][j](j=1<<(a[i]1),s&j==0)

转移方程写对了,代码自然是水到渠成。

Question: 标程的解法看起来像O(n^2)的,为什么比我的快?

#include <bits/stdc++.h>using namespace std;#define RE(x) freopen(x,"r",stdin)#define WR(x) freopen(x,"w",stdout)#define INF 0x3f3f3f3f#define CLEAR(x) memset(x,0,sizeof(x))#define pb push_back#define mp make_pairtypedef long long ll;typedef vector<int> vi;typedef vector<ll> vl;typedef pair<int,int> pii;const int M = 1e9+7;const double PI = acos(-1.0);const double eps = 1e-8;int n;int a[100005];int dp[100005][513];int main() {    //RE("in.txt");WR("out.txt");    cin>>n;    for(int i=1;i<=n;i++) {        cin>>a[i];    }    dp[1][1<<(a[1]-1)]=1;    for(int i=2;i<=n;i++) {        int s=1<<(a[i]-1);        for(int j=1;j<=512;j++) {            dp[i][s]+=dp[i-1][j];            dp[i][s]%=M;            if(!(s&j))                dp[i][s|j]=dp[i-1][j];        }    }    ll ans=0;    for(int i=1;i<=512;i++) {        ans+=dp[n][i];    }    cout<<ans%M<<endl;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

C.分金子(区间DP)

题目描述

A、B两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成n段,由A、B开始轮流从最左端或最右端占据一段,直到分完为止。 
马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)

题目解析:

这道题临场的时候没看懂题意,直接交卷了QAQ.

就是给你n段数,A,B两人轮流选择,可以选最左的或者最右的,每次都选择对己方最有利的策略。问AB最后各有多少金子?

令dp[i][j]表示当前还剩的金矿是区间[i,j]时,A取得的最大收益。这个转移要考虑此时该A拿还是该B拿。

如果该A拿,则有dp[i][j]=max(dp[i+1][j]+a[i],dp[i][j-1]+a[j]);如果该B拿,则有dp[i][j]=min(dp[i+1][j],dp[i][j-1]);,因为B拿哪边都不会增加A的收益,而他要使A尽量拿的小。

那么如何判断该A拿还是该B拿呢,这就与n和区间长度的奇偶关系有关了。观察到,如果n是偶数,则区间长度是偶数时轮到A拿,否则轮到B拿,n是奇数反之。所以该谁拿取决于n和当前区间长度的奇偶关系。在这里因为大区间只依赖于长度比他小1的小区间,所以自底向上枚举区间长度即可。

#include <bits/stdc++.h>using namespace std;#define RE(x) freopen(x,"r",stdin)#define WR(x) freopen(x,"w",stdout)#define INF 0x3f3f3f3f#define CLEAR(x) memset(x,0,sizeof(x))#define pb push_back#define mp make_pairtypedef long long ll;typedef vector<int> vi;typedef vector<ll> vl;typedef pair<int,int> pii;const int M = 1e9+7;const double PI = acos(-1.0);const double eps = 1e-8;int dp[555][555];int T,n;int a[555];int main() {    //RE("in.txt");WR("out.txt");    cin>>T;    for(int i=1;i<=T;i++) {        cin>>n;        int sum = 0;        for(int i=0;i<n;i++) {            cin>>a[i];            sum+=a[i];        }        memset(dp,0,sizeof(dp));        //dfs(0,n-1,1);        if(n&1) {            for(int i=0;i<n;i++) {                dp[i][i]=a[i];            }        }        for(int i=1;i<n;i++) {            for(int j=0;j+i<n;j++) {                if(((n+i)&1)==0) {                    dp[j][j+i]=min(dp[j+1][j+i],dp[j][j+i-1]);                }                else {                    dp[j][j+i]=max(dp[j+1][j+i]+a[j],dp[j][j+i-1]+a[j+i]);                }            }        }        cout<<"Case #"<<i<<": "<<dp[0][n-1]<<" "<<sum-dp[0][n-1]<<endl;    }}
原创粉丝点击