HHTC_学校集训编程题目(13)(组队赛_3)

好久没写博客了,越来越懒了~~
在这里插入图片描述

C - Wandering Robot

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于有些变量复制不了,就截图了~
其实也算是找规律吧,注意一些细节问题就好
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long n,k;
		string s;
		cin>>n>>k;
		cin>>s;
		long long x=0,y=0;
		long long length=0;
		for(int i=0;i<s.length();i++)
		{
			if(s[i]=='U')
				y++;
			else if(s[i]=='D')
				y--;
			else if(s[i]=='L')
				x--;
			else if(s[i]=='R')
				x++;
			if(abs(x)+abs(y)>length)
                length=abs(x)+abs(y);
		}
		x=x*(k-1);
		y=y*(k-1);
		for(int i=0;i<s.length();i++)
		{
			if(s[i]=='U')
				y++;
			else if(s[i]=='D')
				y--;
			else if(s[i]=='L')
				x--;
			else if(s[i]=='R')
				x++;
			if(abs(x)+abs(y)>length)
                length=abs(x)+abs(y);
		}
		cout<<length<<endl;
	}
	return 0;
}

G - Circle

在半径为 1 的圆上有 n 个点,它们也是圆的 n 等分点,将每个相邻的 n 等分点相连,组成了一个正 n边形,现在你可以在圆上再增加一个点,使得新的 n + 1 边形的面积最大,请输出最大面积。

Input

输入有多组(不超过 100 组)。
每组数据一行一个整数 n 代表点的数量。
3 ≤ n ≤ 100

Output

每组数据输出一行一个数表示加上一个点后的最大面积,结果保留6位小数。

Sample Input

3

Sample Output

1.732051

题目意思很好理解,就是将各个点连接起来求面积~~
通过画图就能够发现,就是n-1个三角形加上一个四边形
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

#define PI acos(-1.0)

int main()
{
	int n;
	while(scanf("%d",&n) != EOF){
        double sum = (n-1)*1.0/2*sin(2*PI/n) + sin(PI /n);
        printf("%.6f\n",sum);
	}
	return 0;
}

B - 迷宫寻宝

洪尼玛今天准备去寻宝,在一个n*n (n行, n列)的迷宫中,存在着一个入口、一些墙壁以及一个宝藏。由于迷宫是四连通的,即在迷宫中的一个位置,只能走到与它直接相邻的其他四个位置(上、下、左、右)。现洪尼玛在迷宫的入口处,问他最少需要走几步才能拿到宝藏?若永远无法拿到宝藏,则输出-1。

Input

多组测试数据。
每组数据输入第一行为正整数n,表示迷宫大小。
接下来n行,每行包括n个字符,其中字符’.‘表示该位置为空地,字符’#'表示该位置为墙壁,字符’S’表示该位置为入口,字符’E’表示该位置为宝藏,输入数据中只有这四种字符,并且’S’和’E’仅出现一次。
n≤1000

Output

输出拿到宝藏最少需要走的步数,若永远无法拿到宝藏,则输出-1。

Sample Input

5
S.#..
#.#.#
#.#.#
#...E
#....

Sample Output

7

应该也算是一个bfs的模板题吧
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

const int INF = 0x3f3f3f3f;
char a[1005][1005];
int d[4][2] = {0,1,0,-1,1,0,-1,0};
int vis[1005][1005];
int c[1005][1005];
int ans,n,startx,starty,endx,endy;
typedef pair<int, int> P;

void bfs(){
    queue<P> que;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            c[i][j] = INF;
    que.push(P(startx,starty));
    c[startx][starty] = 0;
    while(!que.empty()){
        P p = que.front();
        que.pop();
        int i;
        for(i=0;i<4;i++){
            int xx = p.first + d[i][0];
            int yy = p.second + d[i][1];
            if(xx < 0 || xx >= n || yy < 0 || yy >= n)
                continue;
            if(vis[xx][yy] == 0 && c[xx][yy] == INF){
                que.push(P(xx,yy));
                c[xx][yy] = c[p.first][p.second] + 1;
                if(startx == endx && starty == endy)
                    break;
            }
        }
        if(i != 4)
            break;
    }
}

int main()
{
    while(scanf("%d",&n) != EOF){
        getchar();
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                scanf("%c",&a[i][j]);
                if(a[i][j] == 'S'){
                    startx = i;
                    starty = j;
                }
                if(a[i][j] == 'E'){
                    endx = i;
                    endy = j;
                }
                if(a[i][j] == '#')
                    vis[i][j] = 1;
            }
            getchar();
        }
        bfs();
        if(c[endx][endy] == INF)
            printf("-1\n");
        else
            printf("%d\n",c[endx][endy]);
    }
    return 0;
}

D - 给力的移动

你的弟弟给你安排了一个任务,他给了你1到N个数字的乱序排列,现在你想给你的弟弟秀一波操作,操作最少的次数把序列变成1到N的顺序排列,每次操作你可以选择序列中的一个数字并把它移动到序列的头部或尾部。

Input

包含多组测试数据。
每组测试数据的第一行为正整数N,表示排列的长度。
第二行为N个数字的乱序排列。
n≤100000

Output

输出最少的操作次数

Sample Input

6
6 3 2 4 5 1

Sample Output

3

因为是递增,所以有一些数的位置是不用变动的,比如样例里面的3 4 5就不需要动
所以我们将最长递增序列的长度求出来,用n减掉就是答案啦
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

int a[100005];
int b[100005];

int main()
{
    int n;
    while(scanf("%d",&n) != EOF){
        memset(b,0,sizeof(b));
        int maxx = 0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[a[i]] = b[a[i] - 1] + 1;
            maxx = max(b[a[i]],maxx);
        }
        printf("%d\n",n - maxx);
    }
    return 0;
}

E - 谁还不是个宝宝

洪尼玛有n个朋友,n个朋友排成一排,每个朋友都有一个自身的价值Ai,并且每个朋友自身的价值均不相同。现在每个朋友都能与他左右的若干个人组成一个区间,也可以他自己一个人组成一个区间。若这个区间的人数为奇数个,那么我们称其为“可行区间”。将一个 “可行区间”里所有朋友按价值排序后,中间的那个朋友就是这个“可行区间”里的“宝宝”。求每个朋友是多少个“可行区间”里的“宝宝”?

Input

多组测试数据。
每组数据输入第一行为正整数n,表示朋友个数。
接下来一行,有n个互不相同的正整数Ai,表示第i个朋友的价值
n≤1000,Ai≤10^9

Output

输出n个正整数,依次表示第i个朋友是多少个“可行区间”里的“宝宝”。

Sample Input

5 
1 2 3 4 5

Sample Output

1 2 3 2 1

Hint

例如3能组成的“可行间”有:{3},{1,2,3},{2,3,4},{3,4,5},{1,2,3,4,5} 共5个区间,其中在{3},{2,3,4},{1,2,3,4,5} 这3个“可行区间”里是宝宝。

利用中位数的思想
从左边右边两边去找,遍历即可
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

const int N = 1e3+5;
int a[N],sum[2*N];
int ans[N];

int main()
{
    int n;
    while(scanf("%d",&n) != EOF){
        memset(ans,0,sizeof(ans));
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++){
            int num = 0;
            memset(sum,0,sizeof(sum));
            for(int j = i - 1;j >= 0; j--){
                if(a[j] < a[i])
                    num--;
                else
                    num++;
                if(!num)
                    ans[i]++;
                sum[num + N]++;
            }
            //cout<<num<<" ";
            num = 0;
            for(int j = i+1; j<n;j++){
                if(a[j] < a[i])
                    num--;
                else
                    num++;
                if(!num)
                    ans[i]++;
                ans[i] += sum[N - num];
            }
            //cout<<num<<endl;;
        }
        for(int i=0; i<n; i++)
        {
            if(i != n-1)
                printf("%d ",ans[i]+1);
            else
                printf("%d\n",ans[i]+1);
        }
    }
    return 0;
}

K - Teamwork

在Farmer John最喜欢的节日里,他想要给他的朋友们赠送一些礼物。由于他并不擅长包装礼物,他想要获得他的
奶牛们的帮助。你可能能够想到,奶牛们本身也不是很擅长包装礼物,而Farmer John即将得到这一教训。Farmer
John的N头奶牛(1≤N≤104)排成一行,方便起见依次编号为1…N。奶牛i的包装礼物的技能水平为si。她们的技
能水平可能参差不齐,所以FJ决定把她的奶牛们分成小组。每一组可以包含任意不超过K头的连续的奶牛(1≤K≤1
03),并且一头奶牛不能属于多于一个小组。由于奶牛们会互相学习,这一组中每一头奶牛的技能水平会变成这一
组中水平最高的奶牛的技能水平。请帮助FJ求出,在他合理地安排分组的情况下,可以达到的技能水平之和的最大
值。

Input

输入的第一行包含N和K。
以下N行按照N头奶牛的排列顺序依次给出她们的技能水平。技能水平是一个不超过10^5的正整数。

Output

输出FJ通过将连续的奶牛进行分组可以达到的最大技能水平和。

Sample Input

7 3
1
15
7
9
2
5
10

Sample Output

84

hint

在这个例子中,最优的方案是将前三头奶牛和后三头奶牛分别分为一组,中间的奶牛单独成为一组(注意一组的奶
牛数量可以小于K)。这样能够有效地将7头奶牛的技能水平提高至15、15、15、9、10、10、10,和为84

DP~
只需要找连续的k头最大的即可,怎么说呢,
表达能力有限,表达不是太清楚,还是按照公式去理解吧
dp[i]=max(dp[i],dp[i-(i-j+1)]+mmax*(i-j+1));
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=1e4+10;
int a[maxn];
int dp[maxn];

int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++){
        int mmax=-1;
        for(int j=i;j>i-k&&j>=1;j--){
            mmax=max(mmax,a[j]);
            dp[i]=max(dp[i],dp[i-(i-j+1)]+mmax*(i-j+1));
            //cout<<dp[i]<<" ";
        }
        //cout<<endl;
    }
    /*for(int i=1;i<=n;i++)
        cout<<dp[i]<<" ";
    cout<<endl;*/
    printf("%d\n",dp[n]);
    return 0;
}

G - Daxia want to buy house

daxia想买房,贷款需满足如下要求,在给出总价等各种需要数据的情况下,请帮他计算需要的首付和月供.

  1. 采用等额本息还款法:
    等额本息还款法:
    即把按揭贷款的本金总额与利息总额相加,然后平均分摊到还款期限的每个月中,每个月的还款额是固定的,但每月还款额中的本金比重逐月递增、利息比重逐月递减.
    计算公式:
    每月还款额=贷款本金×[月利率×(1+月利率)还款月数]÷[(1+月利率)还款月数-1]
  2. 由于商业贷款利率高于公积金贷款利率,优先公积金贷款,超出部分再采用商业贷款.
  3. 银行至多给予贷款总额最多不超过70%,且数额必须为万的整数倍,daxia想尽量少首付多贷款.

Input

测试包含多组数据,每组数据仅一行price_house, max_fund, rate_business, rate_fund, year. 如下详述:
price_house: 100 <= price_house <= 500, 整数, 表示房子总价,单位(万元);
max_fund: 50 <= max_fund <= 100, 整数, 表示公积金最多贷款数额,单位(万元);
rate_business:0 < rate_business < 10, 三位小数的浮点数,表示商业贷款年利率为rate_business%;
rate_fund: 0 < rate_fund < rate_business, 三位小数的浮点数,表示公积金贷款年利率为rate_fund%;
year: 20 <= year <= 30, 整数,表示贷款年限.

Output

每组数据输出一行两个整数first_pay, month_pay.
first_pay: 首付金额,单位(万元)
month_pay: 月供金额,单位(元),请四舍五入.

Sample Input

225 50 4.263 3.25 20

Sample Output

68 9469

Hint

样例各个金额如下:
房子总价 225
首付 68
商业贷款 107
公积金贷款 50
商贷月供 6633
公积金月供 2836

模拟即可,不过要注意精度问题
处理好细节问题
AC代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;

double Pow(double x,double y){
    double ans = x;
    for(int i=1;i<y;i++)
        ans *= x;
    return ans;
}

int main(){
    int n,m,year;
    double r1,r2;
    while(scanf("%d %d %lf %lf %d",&n,&m,&r1,&r2,&year) != EOF){
        int ans = n - (n * 7 / 10);
        r1 /= 1200;
        r2 /= 1200;
        int month = year * 12;
        double sum1 = n - ans - m;
        double sum2 = m;
        if(sum1 < 0){
            sum1 = 0;
            sum2 = n - ans;
        }
        sum1 = sum1 * 10000 * (r1 * Pow(1 + r1,month)) / (Pow(1+r1,month) - 1);
        sum2 = sum2 * 10000 * (r2 * Pow(1 + r2,month)) / (Pow(1+r2,month) - 1);
        printf("%d %d\n",ans,(int)(sum1+sum2+0.50000001));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值