计信院程序设计大赛题解

13 篇文章 0 订阅

第一次出题,原来听说有高中OI的同学参加,所以多准备了几道题,这些题我看来其实不难,不过最后正式比的时候,榜有点那看= =,这里给大家道个歉了~~~~

其实主要是参加的同学都没有在OJ做题的经验。比赛使用的平台是HUST的开源OJ,不支持类似CF的多点判题,所以输入输出我都按标准ACM的方式进行的。

输入方式(以a+b为例)如下:

C:

while(scanf("%d%d",&a,&b)!=eof){

      printf("%d\n",a+b);

}

C++:

while(~scanf("%d%d",&a,&b)){

      printf("%d",a+b);

}

或者

while(cin>>a>>b){

      cout<<a+b<<endl;

}


JAVA:
public class Main 
{
   public static void main(String[] args) 
   {
      Scanner cin = new Scanner(System.in);
      while(cin.hasNext()){
      int a = cin.nextInt();int b = cin.nextInt();
      //System.out.println(a+b); 
      System.out.printf("%d\n",a+b); }
   }
}

看了很多用JAVA的提交,用的是while(true),这样肯定是不能AC的- -

然后开始说题目。题目难度不是按字母顺序排列的,以下按难度给出题解。

B:

B题事实上是最简单的,前面扯了一堆线段树的东西,都是没用的,吓唬吓唬大家的。。我在题干中着重加粗了“其实不用线段树”,结果还是没人做。。

题目的意思是给定一个数列,对于每个给定的区间,求区间的和。

对于这种情况,我们只要一开始预处理从1到ai的和就行了。用一个sum[i]数组表示1加到a[i]的和,注意要用递推,不能二重循环跑,不然复杂度o(n^2)。

sum[i+1]=a[i]+sum[i] 这是递推公式。

然后对于每个L,R,只要输出sum[R]-sum[L-1]就行了。。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long 
#define maxn 100005
LL a[maxn];
LL sum[maxn];
int main()
{
    int n,m,l,r;
    while(~scanf("%d",&n))
    {
        memset(sum,0,sizeof(sum));
        memset(a,0,sizeof(a));
        for(int i = 1; i <= n; i++)
            scanf("%lld",&a[i]);
        sum[0] = 0;
        sum[1] = a[1];
        for(int i = 2; i <= n; i++)
            sum[i] = sum[i-1] + a[i];
        scanf("%d",&m);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d %d",&l,&r);
            printf("%lld\n",sum[r]-sum[l-1]);
        }
    }
    return 0;
}

A:

A题其实也不难,只要统计输入的字母的个数,每次取个数最多的字母,用ans算每次取的字母的个数的平方和,最后不够取完某个字母的时候,就取这个字母的部分就OK了。注意排序的时候最好用快速排序(虽然说这题用交换排序没有任何问题)。

出题的时候设置了很多坑,比如说结果范围要是long long的范围,同时计算的时候也要用long long 强制转换,不然过程还是会爆,真正比的时候看大家都没做出来,就把数据改弱了= = 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long 
int main()
{
    LL n, k;
    LL a[27];
    char s[100017];
    while(~scanf("%lld%lld",&n,&k))
    {
        memset(a,0,sizeof(a));
        scanf("%s",s);
        for(int i = 0; i < n; i++)
        {
            a[s[i]-'A']++;
        } //统计字母
        sort(a,a+26);//排序字母
        LL ans = 0;
        for(int i = 25; i >= 0; i--)
        {
            if(k >= a[i])
            {
                ans+=a[i]*a[i];
                k -= a[i];
                if(k == 0)
                    break;
            }
            else
            {
                ans+=k*k;//特殊判定只有一个字母,如n=10,全部都是A,k=7,
                break;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C

C题事实上也是简单的,只不过大家都没用过STL里的map = =,

map可以对Int或者string进行计数,并且按升序排列,所以只要懂一点map,10分钟之内肯定搞定。。

代码:

#include <map>
#include <string>
#include <iostream>
#include <stdio.h>
using namespace std;
int main(){
    string s;
    map<string,int>m;
    map<string,int>::iterator it;
    while(cin>>s)
    {
        if(s == "0") break;
        if(s == "#") 
        {
            cout<<m.size()<<endl;
            for(it = m.begin(); it != m.end(); it++)
            {
                cout<<it->first<<" "<<it->second<<endl;
            }
            m.clear();
        }
        else    m[s]++;
    }
}
D:

D题稍微有点复杂,要找到可以逆序的区间。

事实上我们只要进行一个处理,对当前的数列进行排序一次,然后从前往后找第一个不同的数字,从后往前找第一个不同的数字,就是区间了。

例如:

1 2 4 3 5

排序后 1 2 3 4 5

从前扫就找到3,从后扫找到5,所以这就是区间了,然后特殊情况处理一下即可。

#include <cstdio>
 #include <cstring> 
 #include <algorithm> 
using namespace std; 
const int maxn = 1e5+5; 
int n, arr[maxn], pos[maxn]; 
bool judge (int l, int r) { 
	for (int i = 0; i + l <= r; i++) { 
		if (arr[l+i] != pos[r-i]) 
			return false; 
	} return true; 
} 
int main () { 
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	while(~scanf("%d", &n))
	{
		memset(arr,0,sizeof(arr));
		memset(pos,0,sizeof(pos));
		for (int i = 0; i < n; i++) { 
			scanf("%d", &arr[i]); pos[i] = arr[i]; 
		} 
		sort(pos, pos + n); 
		int l = 0, r = n-1; 
		while (l < n && pos[l] == arr[l]) l++; 
		while (r >= 0 && pos[r] == arr[r]) r--; 
		if (judge(l, r)) { 
			if (r < l) l = r = 0; 
			printf("yes\n%d %d\n", l+1, r+1); 
		} else 
			printf("no\n"); 		
	}
	return 0; 
	}
其他三题有点难,等稍后给出题解~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值