第一次出题,原来听说有高中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;
}
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;
}
其他三题有点难,等稍后给出题解~