zoukankan      html  css  js  c++  java
  • 【初赛】完善程序题解题技巧 && 近六年PJ完善程序真题解析

    完善程序,每年两题,每题每空2-4分,共28分。

    【解题步骤】

    1、读题:解决什么问题?题目给出了什么算法?输入如何转化输出?

    2、明确变量的含义,通过变量单词的意思猜测;

    3、大致想想:如果让你实现程序,你会怎么做。

    4、通读程序,理顺程序结构,千万不要因为程序很长而觉得气馁,有时程序越长,填空越简单

    5、按照程序执行的顺序做,遇到难的先放一边。有些空格很简单,一下就能看出来的。

    6、根据对程序的理解(结合自己已知的算法)大胆猜测,小心验证地填上很难的几个空

    7、填完了以后,再执行一遍程序,有样例就结合样例,没样例就自己造数据模拟。

    【解题技巧】

    1、变量初始化:这个得结合后面的运算确定,不过有些也很简单,如sum=0之类的。

    2、for循环初、终值:如果是嵌套的循环,可结合父循环或子循环确定。

    3、更新最优解:比较或赋值。

    4、要填的空格与某句对应,这样的例子在下面能找到很多。

    (大整数开方)

    输入一个正整数n(1≤n≤10100),试用二分法计算它的平方根的整数部分。

    #include<iostream>
    #include<string>
    using namespace std;
    
    const int SIZE=200;
    struct hugeint{
        int len,num[SIZE];
    };
    //其中len表示大整数的位数;num[1]表示个位,num[2]表示十位,以此类推
    
    hugeint times(hugeint a,hugeint b)
    // 计算大整数a和b的乘积
    {
        int i,j;
        hugeint ans;
        memset(ans.num,0,sizeof(ans.num));
        for(i=1;i<=a.len;i++)
           for(j=1;j<=b.len;j++)
                [      ①     ] +=a.num[i]*b.num[j];  
        for(i=1;i<=a.len+b.len;i++){
            ans.num[i+1]+=ans.num[i]/10;
            [         ②         ]; 
        }
        if(ans.num[a.len+b.len]>0)
            ans.len=a.len+b.len;
        else
            ans.len=a.len+b.len-1;
        return ans;
    }
    
    hugeint add(hugeint a,hugeint b)
    //计算大整数a和b 的和
    {
        int i;
        hugeint ans;
        memset(ans.num,0,sizeof(ans.num));
        if(a.len>b.len)
            ans.len=a.len;
        else
            ans.len=b.len;
        for(i=1;i<=ans.len;i++){
            ans.num[i]+= [        ③      ] ; 
            ans.num[i+1]+= ans.num[i]/10;
            ans.num[i]%=10;
        }
        if(ans.num[ans.len+1]>0)
            ans.len++;
        return ans;
    }
    
    hugeint average(hugeint a,hugeint b)
    //计算大整数a和b的平均数的整数部分
    {
        int i;
        hugeint ans;
        ans=add(a,b);
        for(i=ans.len;i>=2;i--){
            ans.num[i-1]+=([     ④      ])*10; 
    
            ans.num[i]/=2;
        }
        ans.num[1]/=2;
        if(ans.num[ans.len]==0)
            ans.len--;
        return ans;
    }
    
    hugeint plustwo(hugeint a)
    // 计算大整数a加2之后的结果
    {
        int i;
        hugeint ans;
        ans=a;
        ans.num[1]+=2;
        i=1;
        while( (i<=ans.len)&&(ans.num[i]>=10) ){
            ans.num[i+1]+=ans.num[i]/10;
            ans.num[i]%=10;
            i++;
        }
        if(ans.num[ans.len+1]>0)
            [      ⑤    ]; 
        return ans;
    }
    
    bool over(hugeint a,hugeint b)
    // 若大整数a>b则返回true,否则返回false
    {
        int i;
        if([      ⑥     ])  
            return false;
        if( a.len>b.len )
            return true;
        for(i=a.len;i>=1;i--){
            if(a.num[i]<b.num[i])
               return false;
            if(a.num[i]>b.num[i])
               return true;
        }
        return false;
    }
    
    int main()
    {
        string s;
        int i;
        hugeint target,left,middle,right;
        cin>>s;
        memset(target.num,0,sizeof(target.num));
        target.len=s.length();
        for(i=1;i<=target.len;i++)
            target.num[i]=s[target.len-i]-[      ⑦    ];
        memset(left.num,0,sizeof(left.num));
        left.len=1;
        left.num[1]=1;
        right=target;
        do{
            middle=average(left,right);
            if(over([       ⑧        ]))
                right=middle;
            else
                left=middle;
        }while(!over(plustwo(left),right) );
        for(i=left.len;i>=1;i--)
           cout<<left.num[i];
        return 0;
    }
    

    ans.num[i+j]xxxxxxxxxxxxxxxx
    corect:ans.num[i+j-1]
    2.
    ans.num[i]%=10
    3.
    a.num[i]+b.num[i]
    4.
    ans.num[i]%2
    5.
    ans.len++
    6.
    a.len<b.len
    7.
    '0'
    8.
    times(middle,middle),target

    得分:16/18

    [noip 2013 PJ 第 28 题](#noip 2013 PJ 第 28 题)

    #include <iostream> 
    using namespace std; 
    const int SIZE = 100;
    const int INFINITE = 1000000;
    struct node
    {
    	int left_child, right_child, value;
    }; node a[SIZE];
    int is_bst( int root, int lower_bound, int upper_bound )
    {
    	int cur;
    	if ( root == 0 )
    		return(1);
    	cur = a[root].value;
    	if ( (cur > lower_bound) && ( ① ) && (is_bst( a[root].left_child, lower_bound, cur ) == 1) && (is_bst( ②, ③, ④ ) == 1) )
    		return(1);
    	return(0);
    }
    
    
    int main()
    {
    	int i, n; cin >> n;
    	for ( i = 1; i <= n; i++ )
    		cin >> a[i].value >> a[i].left_child >> a[i].right_child;
    	cout << is_bst( ⑤, -INFINITE, INFINITE ) << endl;
    	return(0);
    }
    

    cur<upper_bound
    2.
    a[root].right
    3.
    cur
    4.
    upper_bound
    5.
    1

    [noip 2014 PJ 第 27 题](#noip 2014 PJ 第 27 题)

    ' '为 TAB 制表符

    完善程序:
    (打印日历) 输入月份 m(1≤m≤12),按一定格式打印 2015 年第 m 月的月历。(第三、四空 2.5 分, 其余 3 分)
    例如,2015 年 1 月的月历打印效果如下(第一列为周日):

    S M T W T F S
    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

    #include <iostream>
    #include <string>
    using namespace std;
    const int dayNum[] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int m, offset, i;
    int main()
    {
        cin >> m;
        cout << "S	M	T	W	T	F	S" << endl; /* '	'为 TAB 制表符 */
        ①;
        for (i = 1; i < m; i++)
            offset = ②;
        for (i = 0; i < offset; i++)
            cout << '	';
        for (i = 1; i <= ③; i++)
        {
            cout << ④;
            if (i == dayNum[m] || ⑤ == 0)
                cout << endl;
            else
                cout << '	';
        }
        return (0);
    }
    

    offset=4
    2.
    (offset+dayNum[i])%7
    3.
    dayNum[m]
    4.
    i
    5.
    (offset+i)%7

    得分:14/14

    [整数二分算法模板 —— 模板题 AcWing 789. 数的范围](#整数二分算法模板 —— 模板题 AcWing 789. 数的范围)

    bool check(int x) {/* ... */} // 检查x是否满足某种性质
    
    // 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
    int bsearch_1(int l, int r)
    {
        while (l < r)
        {
            int mid = l + r >> 1;
            if (check(mid)) r = mid;    // check()判断mid是否满足性质
            else l = mid + 1;
        }
        return l;
    }
    // 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
    int bsearch_2(int l, int r)
    {
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        return l;
    }
    
    

    [浮点数二分算法模板 —— 模板题 AcWing 790. 数的三次方根](#浮点数二分算法模板 —— 模板题 AcWing 790. 数的三次方根)

    bool check(double x) {/* ... */} // 检查x是否满足某种性质
    
    double bsearch_3(double l, double r)
    {
        const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
        while (r - l > eps)
        {
            double mid = (l + r) / 2;
            if (check(mid)) r = mid;
            else l = mid;
        }
        return l;
    }
    

    [noip 2014 PJ 第 28 题](#noip 2014 PJ 第 28 题)

    注意避免二分死循环,就算你写的二分不会死循环,但是初赛的二分写法妖艳的很

    完善程序:
    (中位数 median) 给定 n(n 为奇数且小于 1000)个整数,整数的范围在 0~m(0<m<2^31)之间,请使用二分法求这 n 个整数的中位数。所谓中位数,是指将这 n 个数排序之后,排在正中间的数。(第五空 2分,其余 3 分)

    #include <iostream>
    using namespace std;
    
    const int MAXN = 1000;
    int n, i, lbound, rbound, mid, m, count;
    int x[MAXN];
    
    int main()
    {
        cin >> n >> m;
        for (i = 0; i < n; i++)
            cin >> x[i];
        lbound = 0;
        rbound = m;
        while (①)
        {
            mid = (lbound + rbound) / 2;
            ②;
            for (i = 0; i < n; i++)
                if (③)
                    ④;
            if (count > n / 2)
                lbound = mid + 1;
            else
                ⑤;
            cout << mid << " " << lbound << " " << rbound << " " << count << endl;
        }
        cout << rbound << endl;
        return (0);
    }
    
    

    lbound<rbound
    2.
    count=0
    3.
    x[i]>mid
    4.
    count++
    5.
    rbound=mid

    第 28 题

    完善程序: (郊游活动)有 n 名同学参加学校组织的郊游活动,已知学校给这 n 名同学 的郊游总经费为 A 元,与此同时第 i 位同学自己携带了 Mi 元。为了方便郊 游,活动地点提供 B(≥n)辆自行车供人租用,租用第 j 辆自行车的价格为 Cj 元,每位同学可以使用自己携带的钱或者学校的郊游经费,为了方便账务管 理,每位同学只能为自己租用自行车,且不会借钱给他人,他们想知道最多 有多少位同学能够租用到自行车。(第四、五空 2.5 分,其余 3 分)
    本题采用二分法。对于区间[l, r],我们取中间点 mid 并判断租用到自行 车的人数能否达到 mid。判断的过程是利用贪心算法实现的。

    #include <iostream>
    using namespace std;
    #define MAXN 1000000
    
    int n, B, A, M[MAXN], C[MAXN], l, r, ans, mid;
    
    bool check(int nn) {
    	int count = 0, i, j;
    	i = ①;
    	j = 1;
    	while (i <= n) {
    		if(②)
    			count += C[j] - M[i];
    		i++;
    		j++;
    	}
    	return ③;
    }
    	
    void sort(int a[], int l, int r) {
    	int i = l, j = r, x = a[(l + r) / 2], y;
    	while (i <= j) {
    		while (a[i] < x) i++;
    		while (a[j] > x) j--;
    		if (i <= j) {
    			y = a[i]; a[i] = a[j]; a[j] = y;
    			i++; j--;
    		}
    	}
    if (i < r) sort(a, i, r);
    if (l < j) sort(a, l, j);
    }
    
    int main() {
    	int i;
    	cin >> n >> B >> A;
    	for (i = 1; i <= n; i++)
    		cin >> M[i];
    	for (i = 1; i <= B; i++)
    		cin >> C[i];
    	sort(M, 1, n);
    	sort(C, 1, B);
    	l = 0;
    	r = n;
    	while (l <= r) {
    		mid = (l + r) / 2;
    		if(④){
                ans = mid;
    			l = mid + 1;
    		}else
    			r = ⑤;
    	}
    	cout << ans << endl;
    	return 0;
    }
    

    得分:11/13

    分析:第一个空填错了,这里的贪心是指M[i]最大的mid(nn)个人,即用编号为n-mid(nn)+1~n 的个人的钱去怼C[1~B] (从小到大),因为他们是对总花费贡献最小的。

    所以第一空应该填'n-nn+1'

    btw:这里判断的的是mid个人是否可行,所以1~ mid-1的人的花费并不用算(因为压根儿没选他们好不啦)

  • 相关阅读:
    asyncio
    pytz
    celery
    xml
    jsonpath
    requests
    SQLite 数据库存储
    SQLite 数据库存储
    Android 记住密码功能
    Android 记住密码功能
  • 原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11667854.html
Copyright © 2011-2022 走看看