2019年湘潭大学程序设计竞赛(重现赛)部分题解(A、B、C、D、F)

2019年湘潭大学程序设计竞赛(重现赛)

由于本人水平比较菜,只做出了5个,剩下的不太会了。写简单题的题解主要是给本校学弟学妹学习学习的。

A、B水题就不解释了;

代码比较丑,轻喷

A:A本来是想写一个结构题排下序的,后来发现重载那里比较难写,就换了下面这一种

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,p,s;
int n1,p1,s1;
struct node
{
	int id,x,y,z;
}a[3];
int main()
{
	for(int i=1;i<=2;i++) 
	{
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
		a[i].id=i;
	}
	if(a[1].x<a[2].x)
	{
		printf("2\n");
		return 0;
	}
	if(a[1].x>a[2].x)
	{
		printf("1\n");
		return 0;
	}
	if(a[1].y<a[2].y) 
	{
		printf("1\n");
		return 0;
	}
	if(a[1].y>a[2].y)
	{
		printf("2\n");
		return 0;
	}
	if(a[1].z<a[2].z)
	{
		printf("1\n");
		return 0;
	}
	if(a[1].z>a[2].z)
	{
		printf("2\n");
		return 0;
	}
	printf("God\n");
	return 0;
}

B:

#include <bits/stdc++.h>
using namespace std;
int main(){
	int t;cin>>t;
	while(t--)
	{
		int n;int ans=0;
		scanf("%d",&n);
		while(n>1){
			if(n%10!=0)
			{
				ans++;n++;
			}
			while(n%10==0){
				n/=10;
				ans++;
			}
		}
		printf("%d\n",ans);
	}
}

链接:https://ac.nowcoder.com/acm/contest/893/C
来源:牛客网
 

题目描述

已知整数a,a3a,a3除192的余数是1。求区间[L,R]之间满足条件的a的累加和是多少?

输入描述:

第一行是一个整数T(1≤T≤10000)T(1≤T≤10000),表示样例的个数。
每个样例包含两个整数L,R,1≤L≤R≤109L,R,1≤L≤R≤109。

输出描述:

每行输出一个样例的结果。

示例1

输入

复制

1
1 10

输出

复制

1

C题打表找规律,还不会打表的看我代码的注释部分。

至于官方解法,不知道怎么证的。

可以看看

然后还有一个知识点。如果是求(L,R);我们可以求这个(0,R)-(0,L-1)代替(L,R)。好好想想~

还有人找到规律不知道怎么写的吗?

1,193,385,577.等差数都为192.

1,192*1+1,192*2+1,192*3+1......以此类推(等差数列通项)。

先不考虑1,都减一个1.(待会加回来就可以了 加个(L-R+1))

0,192*1,192*2,192*3;

那么只需要统计区间内192的个数*192(前面已经说了(0,R)-(0,L-1)代替(L,R))

这里还有一个知识点。若R/192=num,那么num就是0到R区间内包含192的个数(可以自己去证明几个数玩玩)

 

那么求出num了,答案就是num*(num+1)/2*192+(L-R+1).(num*(num+1)/2是等差数列求和,上了大学,高中知识快忘了吧,快去百度等差数列怎么求和的)

数列就变成了

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e3+10;
const ll inf=1e9;
ll sum[N*40];
int ls[N*40],rs[N*40];
int cnt=0,rt;
/*void init()
{
	for(ll i=1;i<=1e3;i++)
	{
		if((i*i*i)%192==1)
		{
			printf("i:%lld\n",i);
		}
	}
}*/
int main()
{
	int t;
	//init();
	cin>>t;
	while(t--)
	{
		ll l,r;
		scanf("%lld%lld",&l,&r);
		ll n1=0,n2=0;
		if(l>=2) n1=(l-2)/192;
		if(r>=1)	n2=(r-1)/192;
		//printf("n1:%lld\n",n1);
		//printf("n2:%lld\n",n2);
		ll a1=n1*(n1+1)*192/2;
		ll a2=n2*(n2+1)*192/2;
		//printf("a2:%lld a1:%lld\n",a2,a1);
		ll ans=a2-a1+n2-n1;
		if(l==1) ans++;
		printf("%lld\n",ans);
	}
}

下面是许老师的代码,多简洁

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gao(ll n)
{
    int m=n/192;
    if(n%192)
        m++;
    return 1ll*(1+192*(m-1)+1)*m/2;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int l,r;
        cin>>l>>r;
        ll ans=gao(r);
        ans-=gao(l-1);
        cout<<ans<<endl;
    }
}

链接:https://ac.nowcoder.com/acm/contest/893/D
来源:牛客网
 

有n堆石子排成一排,第i堆石子有aiai个石子。
每次,你可以选择任意相邻的两堆石子进行合并,合并后的石子数量为两堆石子的和,消耗的体力等价于两堆石子中石子数少的那个。
请问,将所有的石子合并成一堆,你所消耗的体力最小是多少?

输入描述:

第一行是一个整数T(1≤T≤20)T(1≤T≤20),表示样例的个数。
每个样例的第一行是一个整数n(1≤n≤10000)n(1≤n≤10000),表示石子堆的数量。
第二行是n个整数ai(1≤ai≤109)ai(1≤ai≤109)

输出描述:

每行输出一个样例的结果。

示例1

输入

复制

2
2
1 2
1
1

输出

复制

1
0

说明

巨大的输入,请使用C风格的输入。

感觉题解讲的很清楚了。管你是不是选择相邻的。我永远从最大的那一堆跟它附近的堆合并。最大堆合并一个堆后还是最大的堆。那么代价就不会加上最大堆的值。

所以我的做法是排个序,从1加n-1就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+10;
ll a[N];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			ll x;
			scanf("%lld",&a[i]);
		}
		ll ans=0;
		sort(a+1,a+1+n);
		for(int i=1;i<=n-1;i++) ans+=a[i];
		printf("%lld\n",ans);
	}
}

链接:https://ac.nowcoder.com/acm/contest/893/F
来源:牛客网
 

题目描述

你有一个长度为 n 的 01 串S,你可以执行最多 m 次操作。
对于每次操作,你可以选择一个位置 i 满足 1≤i≤n1≤i≤n,翻转这一位的值,0变成1,1变成0。
定义一个 01 串的价值为其中最长连续0的个数和最长连续1的个数的较大值,求S在经过最多m次操作后的最大价值。

输入描述:

* 第一行一个整数 T ,表示接下来有 T 个样例。
* 首先输入n,m,表示S串的长度n和操作次数m,其中1≤n≤1000001≤n≤100000,0≤m≤10000≤m≤1000;
* 接下来输入一个长度为n的字符串S。

输出描述:

一个整数,表示题面上描述的最大价值。

示例1

输入

复制

2
5 1
00101
2 1
01

输出

复制

4
2

说明

第一个串翻转第三个位置,00001的价值为4;第二个串翻转第一个位置,11的价值为2。

F题我的做法不太正确哈,我是纯暴力。从每一个点出发,要么向左延伸,要么向右延伸,求最大值。时间复杂度:O(1e8);

正确做法请看官方题解:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
char s[N];
int t,a[N],n,m;
struct node
{
	int x,y;
}b[N];
int call(int id,int m)
{
	int pre=a[id];
	int num=1;
	int l=id-1,r=id+1;
	while(m&&l>=1)
	{
		if(a[l]!=pre)m--;
		num++;
		l--;
	}
	while(l>=1&&a[l]==pre)l--,num++;
	while(r<=n&&a[r]==pre) r++,num++;
	return num;
}
int calr(int id,int m)
{
	int pre=a[id];
	int num=1;
	int l=id-1,r=id+1;
	while(m&&r<=n)
	{
		if(a[r]!=pre)m--;
		num++;
		r++;
	}
	while(l>=1&&a[l]==pre)l--,num++;
	while(r<=n&&a[r]==pre) r++,num++;
	return num;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		scanf("%d%d",&n,&m);
		scanf("%s",s+1);
		for(int i=1;i<=n;i++) a[i]=s[i]-'0';
		int ans=0;
		for(int i=1;i<=n;i++)
		{
			int pre=a[i];
			int num=0;
			int a1=call(i,m);
			int a2=calr(i,m);
			num=max(a1,a2);
			ans=max(ans,num);
		}
		printf("%d\n",ans);
	}
}
/*
100

14 6
11110000001111
100
12 1
100001110111
15 1
000100001110111
*/

再贴一下正确做法的代码,来自hsx

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int pref[105000];
 
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        string s;
        cin>>s;
         
        for(int i=0;i<n;i++){
            if(s[i]=='1')   pref[i+1]=pref[i]+1;//统计1的个数 
            else pref[i+1]=pref[i];
        }
         
        int ans=0;
        for(int i=1;i<=n;i++){//这样也阔以咯 
            int l=i;
            int r=n;
            while(l<=r){
                int mid=(l+r)/2;
                if(pref[mid]-pref[i-1] <= m){
                    ans=max(ans,mid-i+1);
                    l=mid+1;
                }
                else r=mid-1;
            }
        }
         
        for(int i=1;i<=n;i++){
            int l=i;
            int r=n;
            while(l<=r){
                int mid=(l+r)/2;
                if((mid-i+1) - (pref[mid]-pref[i-1]) <= m){//0的个数 
                    ans=max(ans,mid-i+1);
                    l=mid+1;
                }
                else r=mid-1;
            }
        }
        printf("%d\n",ans);
    }
     
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章