2019 年百度之星·程序设计大赛 - 初赛一 解题报告

题目链接

1001 Polynomial (基础数学)

Accepts: 2234

Submissions: 5283

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 32768/32768 K (Java/Others)

Problem Description

度度熊最近学习了多项式和极限的概念。 现在他有两个多项式 f(x) 和 g(x),他想知道当 x 趋近无限大的时候,f(x)/g(x) 收敛于多少。

Input

第一行一个整数 T (1≤T≤100) 表示数据组数。 对于每组数据,第一行一个整数 n (1≤n≤1,000),n−1 表示多项式 f 和 g 可能的最高项的次数(最高项系数不一定非0)。 接下来一行 n 个数表示多项式 f,第 i 个整数 fi (0≤fi≤1,000,000) 表示次数为 i−1 次的项的系数。 接下来一行 n 个数表示多项式 g,第 i 个整数 gi (0≤gi≤1,000,000)表示次数为 i−1 次的项的系数。 数据保证多项式 f 和 g 的系数中至少有一项非0。

Output

对于每组数据,输出一个最简分数 a/b(a 和 b 的最大公约数为1)表示答案。 如果不收敛,输出 1/0。

Sample Input

3
2
0 2
1 0
2
1 0
0 2
3
2 4 0
1 2 0

Sample Output

1/0
0/1
2/1

样例描述
这些多项式分别为
f(x)=2xf(x) = 2xf(x)=2x
g(x)=1g(x) = 1g(x)=1
f(x)=1f(x) = 1f(x)=1
g(x)=2xg(x) = 2xg(x)=2x
f(x)=4x+2f(x) = 4x + 2f(x)=4x+2
g(x)=2x+1g(x) = 2x + 1g(x)=2x+1

题意分析:

给出两个多项式各项的系数,求f(x)/g(x)趋近多少。

解题思路:

当两者的最高项都不为0时,趋近与两者之比;

当f(x)最高项为0时趋近0,即0/1,

当g(x)最高项为0时趋近1,即1/0。

此最高项是两者中次数大的项, 注意化简为最简分数。

#include <stdio.h>
#include <algorithm>
#define N 1020
using namespace std;
int a[N], b[N];
int main() {
	int t, n;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		for(int i=0; i<n; i++)
			scanf("%d", &a[i]);
		for(int i=0; i<n; i++)
			scanf("%d", &b[i]);
		for(int i=n-1; i>=0; i--)
		{
			if(a[i]==0 && b[i]==0)
				continue;
			if(a[i]==0)
			{
				printf("0/1\n");
				break;
			}
			
			else if(b[i]==0) {
				printf("1/0\n");
				break;
			}	
			else 
			{
				int c=__gcd(a[i], b[i]);
				printf("%d/%d\n", a[i]/c, b[i]/c);
				break;
			}
		}
	}
	return 0;
}

 

1002 Game (贪心模拟)

Accepts: 572

Submissions: 6218

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 32768/32768 K (Java/Others)

Problem Description

度度熊在玩一个好玩的游戏。 游戏的主人公站在一根数轴上,他可以在数轴上任意移动,对于每次移动,他可以选择往左或往右走一格或两格。 现在他要依次完成 n 个任务,对于任务 i,只要他处于区间 [ai,bi]上,就算完成了任务。 度度熊想知道,为了完成所有的任务,最少需要移动多少次? 度度熊可以任意选择初始位置。

Input

第一行一个整数 T (1≤T≤10)表示数据组数。 对于每组数据,第一行一个整数 n (1≤n≤1000) 表示任务数。 接下来 n 行,第 iii 行两个整数 ai,bi (1≤ai≤bi≤1000000) 表示任务对应的区间。

Output

对于每组数据,一行一个整数表示答案。

Sample Input

1
2
1 10
20 30

Sample Output

5

样例描述
选取10为起点,经过的轨迹为10-12-14-16-18-20。

题意分析:

给出n个区间,初始位置可选,依次到达相应的区间,每次可以移动一格或两格,求最小步数。

解题思路:

因为只要在这个区间中就可以完成任务,第一次的位置可选,所以初始位置可以选前几个任务的相交区间中,这样一次可以完成更多的任务, 此时若所以任务都完成即可结束,否则继续计算。

此时前面所有任务的相交区间是一个可选区间,也就是说初始位置可以选这个区间中的任意一个数,下一个任务不会和此区间重合,因为重合的区间会在前面计算在内,                                                                                                                                        很容易想到如果下一任务在区间右侧,应该选最靠右的点,                                                                                                            同理如果下一任务在区间左侧,应该选最靠左的点。

此时位置已经确定,在考虑任务时,在此区间内自然不用考虑,所以只看两种情况,用sum代表当前位置,两种情况为sum>b[i]和sum < a[i]。

在此有一个可移动步数,如果现在两步两步的移动可以到达箭头指向的地方,下一任务如果是第3个的左边区间,那么这样移动是对的,但如果是右边区间,那么之前移动的最后的2步应该改成1步,也就是说向右移动1步可以使贪心策略最佳,如果这个区间只有一个点,就不能移动。

上面考虑的是下一任务在sum左边的情况,在sum右边时同样可以推出来。

#include <stdio.h>
#include <algorithm>
#define N 1020
using namespace std;
int a[N], b[N];
int main() {
    int t, n, l, r, i;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        scanf("%d%d", &a ,&b);
        
        for(i=1; i<n; i++)
            scanf("%d%d", &a[i], &b[i]);
        l=a[0];r=b[0];
        for(i=1; i<n; i++) {                        //选相交区间
            if(max(l, a[i])>min(r, b[i]))
                break;
            l=max(l, a[i]);
            r=min(r, b[i]);
        }
        if(i==n)                                  //所有任务完成,结束
        {
            printf("0\n");
            continue;
        }
        int ans=0, sum;
        
        if(b[i]<l) 
            sum=l;  
        else sum=r;
        int temp=0;
  
        for(; i<n-1; i++)                     //没有考虑最后一个,因为要用到 i+1 项任务
        {
            if(sum>b[i]) {
                if (temp==-1)                 //步数可以移动
                    sum--;
                ans+=(sum-b[i]+1)/2;           //更新步数
                if((sum-b[i])%2==1 && b[i]-a[i]>=1)      //判断区间只有一个点的情况
                    temp=-1;                       //更新可以移动的步数
                else temp=0;      
                sum=b[i];                        //更新位置
            }
            else if(sum < a[i]) {
                if (temp==1)
                    sum++;
                ans+=(a[i]-sum+1)/2;
 
                if((a[i]-sum)%2==1 && b[i]-a[i]>=1)
                    temp=1;
                else temp=0;
                sum=a[i];
            }
            else {
                if (sum==a[i] && temp==-1)
                    temp=0;
                else if (sum==b[i] && temp==1)
                    temp=0;
            }
        }
        //printf("!%d %d %d\n", sum, ans, temp);
        if(sum>b[i]) {                    //考虑最后一个
            if (temp==-1)
                sum--;
            ans += (sum-b[i] + 1)/2;
        }
        else if(sum<a[i]) {
            if (temp==1)
                sum++;
            ans+=(a[i]-sum+1)/2;
        }
        
        printf("%d\n",ans);
    }
    return 0;
}
/**
3
1 2
2 3
1 1
3
5 6
1 2
7 8
4
1 10
2 8
11 12
12 13

4 
4 4 
5 10 
3 5 
8 10 
*/
 

1005 Seq (找规律)

Accepts: 1283

Submissions: 3956

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 32768/32768 K (Java/Others)

Problem Description

度度熊有一个递推式 其中a​1​​=1。现给出 n,需要求 an。

Input

第一行输入一个整数 T,代表 T (1≤T≤100000组数据。 接下 T 行,每行一个数字 n (1≤n≤10^12)。

Output

输出 T 行,每行一个整数表示答案。

Sample Input

5
1
2
3
4
5

Sample Output

1
1
0
3
0

题意分析:

给出n,求( a[1] * 1 + a[2] * 2 + …… + a[n-1]*(n-1) ) % n;

解题思路:

先打个表出来,依次代表n,n/6,  a[n]。

发现这个每6个是一轮,第一次打表的时候,也是没有发现规律的,最后才加上了中间的n/6。

第一个数是n/2;

第二个数是1+(n/6)* 4;

第三个数是1+(n/6)* 3;

第四个数是(n/6);

第五个数是3+(n/6)*6;

第六个数是n/6。

只要求出对6取余是哪一个数,输出相应的公式即可。

#include <stdio.h>
int main()
{
	int T;
	long long n;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%lld", &n);
		long long t=n/6;
		if(n%6==3 || n%6==5)
			printf("%lld\n", t);
		else if(n%6==0)
			printf("%lld\n", n/2);
		else if(n%6==1)
			printf("%lld\n", 1+t*4);
		else if(n%6==2)
			printf("%lld\n", 1+t*3);
		else if(n%6==4)
			printf("%lld\n", 3+t*6);
	}
	return 0;
}

 

posted @ 2019-08-18 09:54  宿星  阅读(173)  评论(0编辑  收藏  举报