编程语言
首页 > 编程语言> > 杭州电子科技大学计算机学院Debug杯程序设计竞赛

杭州电子科技大学计算机学院Debug杯程序设计竞赛

作者:互联网

杭州电子科技大学计算机学院Debug杯程序设计竞赛

难得ak了,来写一波题解
(感觉会是很长的题解QAQ)

1001.字数补丁

题意

用若干"zsbd"来补全原串使得其大于等于指定长度

题解

暴力模拟,手速题

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

int main()
{	long _=1,__=1,n;
	string s;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		scanf("%ld",&n);
		cin>>s;
		while(s.length()<n)
			s+="zsbd";
		cout<<s<<endl;
	}
	return 0;
}

1002.看电影

题意

给定一个n*m的网格,在可选的点中找两个纵坐标连续的点,使得其最接近网格中心

题解

暴力,把所有点枚举一遍

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 1010
#define calc(i,j,k,l) (abs(i-k)+abs(j-l))
using namespace std;

bool mp[def][def];

int main()
{	long _=1,__=1,n,m,k,i,j,x,y,minn;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		memset(mp,true,sizeof(mp));
		scanf("%ld%ld%ld",&n,&m,&k);
		for(i=1;i<=k;i++){
			scanf("%ld%ld",&x,&y);
			mp[x][y]=false;
		}
		minn=INF;
		for(i=1;i<=n;i++)
			for(j=1;j<m;j++)
				if(mp[i][j]&&mp[i][j+1]&&calc(i,j,(n+1)/2,m/2)<minn){
					minn=calc(i,j,(n+1)/2,m/2);
					x=i;
					y=j;
				}
		if(minn!=INF)
			printf("(%ld,%ld) (%ld,%ld)\n",x,y,x,y+1);
		else
			printf("-1\n");
	}
	return 0;
}

1003.小C与小B的切磋

题意

有很多手牌,一些牌有价值,一些牌没有,有价值的牌只有身处手牌边缘时打出才有价值,每次可以花费\(w_i\)打掉第\(i\)张牌,问在花费不超过\(m\)的情况下能得到的最大价值

题解

显然,每次都从边缘出牌获得的价值才可能最大
因为边缘出牌的牌必定是两段连续的区间,一段从头开始,一段从尾开始,那么剩下的没出的牌肯定是一个连续的区间
于是我们可以用一个滑动区间来模拟未出牌的区间,每次保证在区间外花费不超过\(m\)的情况下,区间最短就好了
从头到尾循环一次,复杂度\(O(n)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 200010
using namespace std;

long a[def],b[def];

int main()
{   long _=1,__=1,n,m,i,l,r;
    ll ans,sum,val,all_sum,all_val;
    for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
        scanf("%ld%ld",&n,&m);
        val=sum=0;
        for(i=1;i<=n;i++){
            scanf("%ld%ld",&a[i],&b[i]);
            if(b[i])
                scanf("%ld",&b[i]);
            val+=b[i];
            sum+=a[i];
        }
        all_sum=sum;
        all_val=val;
        m=all_sum-m;
        ans=sum=val=0;
        for(l=r=1;r<=n;r++){
            sum+=a[r];
            val+=b[r];
            if(sum>=m)
                ans=max(ans,all_val-val);
            while(sum+a[r+1]-a[l]>=m){
                sum-=a[l];
                val-=b[l];
                l++;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

1004.小C的翻转难题

题意

定义数列的魅力值为\(\sum^{n-1}_{i=1}|a_{i+1}-a_{i}|\),允许对数列的连续的一部分进行反转操作,即让选定区间内的所有数前后顺序颠倒,求可能得到的最大魅力值

题解

ps:这应该是这场比赛最考验思维的题了,超多公式警告!!!(建议一边看一边动动笔)
如果有更简单的思路,欢迎讨论

对于一个反转操作区间\([l,r]\),很容易证明\([l+1,r-1]\)这个区间内的魅力值是不变的
那么问题变成了\(a_l, a_{l-1}, a_r, a_{r+1}\)这四个数之间的关系了
对两对单点魅力值列出算式:
令\(i=l-1, j=r\)
改变前:\(ans1=|a_i-a_{a_{i+1}}|+|a_j-a_{j+1}|\)
改变后:\(ans2=|a_i-a_j|+|a_{i+1}-a_{j+1}|\)
那么要求的就是\(ans2-ans1\)的最大值
\(ans2-ans1=|a_i-a_j|+|a_{i+1}-a_{j+1}|-|a_i-a_{a_{i+1}}|-|a_j-a_{j+1}|\)
给\(a\)排个序,可以去掉第一个绝对值,整理一下
原式\(=a_i-|a_i-a_{i+1}|+|a_{i+1}-a_{j+1}|-a_j-|a_j-a_{j+1}|\)
因为\(a_i\)和\(a_{i+1}\)以及\(a_j\)和\(a_{j+1}\)的关系飘忽不定
所以枚举\(a_{i+1}\)和\(a_{j+1}\)的大小关系
1)\(a_{i+1} > a_{j+1}\)
原式\(=(a_i+a_{i+1}-|a_i-a_{i+1}|)-(a_j+a_{j+1}+|a_j-a_{j+1}|)\)
\(=2*min(a_i, a_{i+1})-2*max(a_j,a_{j+1})\)
2)\(a_{i+1} \leq a_{j+1}\)
原式\(=(a_i-a_{i+1}-|a_i-a_{i+1}|)-(a_j-a_{j+1}+|a_j-a_{j+1}|)\)
分情况枚举一下,可知\((a_i-a_{i+1}-|a_i-a_{i+1}|) \leq 0\)且\((a_j-a_{j+1}+|a_j-a_{j+1}|) \geq 0\)
那么这种情况一定为负
综上所述,要找的就是\(2*min(a_i, a_{i+1})-2*max(a_j,a_{j+1})\)
那么既然\(i<j\)且\(a_i>a_j\),就直接从大到小排个序,然后从后往前枚举一遍,维护一下i之后的\(max(a_j,a_{j+1}\)就好了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 500010
using namespace std;

struct node{
	ll x;
	long y;
}a[def],b[def];

int main()
{	long _=1,__=1,n,i;
	ll sum,ans,minn,maxx;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		scanf("%ld",&n);
		sum=0;
		for(i=1;i<=n;i++){
			scanf("%lld",&a[i].x);
			a[i].y=i;
			if(i>1)sum+=abs(a[i].x-a[i-1].x);
		}
		memcpy(b,a,sizeof(a));
		sort(a+1,a+n+1,[&](node a,node b){return a.x>b.x;});
		ans=0;
		minn=INF;
		maxx=0;
		for(i=n;i>=1;i--)
			if(a[i].y<n){
				ans=max(ans,2*min(b[a[i].y].x,b[a[i].y+1].x)-2*minn);
				minn=min(minn,max(b[a[i].y].x,b[a[i].y+1].x));
			}
		printf("%lld\n",sum+ans);
	}
	return 0;
}

5.第二届花园小学运动会

题意

在不同的距离上有很多堆东西,每次可以按照输入顺序拿走\(m\)个,如果拿满了就回到起点(距离为0的点),问拿走所有东西的需要的距离是多少

题解

看起来像一个\(dp\)或者贪心,其实认真读题会发现,顺序是固定的
那么这题就是一个模拟了
需要注意的是,每个点可能不止来回一次(在这wa了几发)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

ll a[def],b[def];

int main()
{	long _=1,__=1,n,m,i,now;
	ll ans;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		scanf("%ld%ld",&n,&m);
		for(i=1;i<=n;i++)
			scanf("%lld",&a[i]);
		for(i=1;i<=n;i++)
			scanf("%lld",&b[i]);
		now=m;
		ans=0;
		for(i=1;i<=n;i++)if(b[i]){
			if(now>b[i]&&i!=n)
				now-=b[i];
			else{
				b[i]=max(0,b[i]-now);
				ans+=2*a[i]*(b[i]/m+1);
				now=m-b[i]%m;
				if(i==n&&now<m)
					ans+=2*a[i];
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

6.阿燕的首都保卫战

题意

若干个城市按树状连接,每个点可以放置\(c_i\)个士兵,敌人进攻的时候,每个点会投入\(p_i\)个士兵,敌我士兵只能一换一,如果一个城市沦陷,剩余的敌方士兵会继续向父节点进攻,如果守城成功,守兵不会移动,问首都是否不会沦陷

题解

树状,向父节点,这两个关键词联系起来就很容易想到用dfs(没想到更高级的算法)
从下往上计算每个点的敌军数量,每个点都判断一下是否沦陷,最后判断首都

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

vector<long>mp[def];
ll a[def],b[def];
long fa[def];

void build(long now)
{
    for(auto next:mp[now])
        if(next!=fa[now]){
            fa[next]=now;
            build(next);
            a[now]+=a[next];
        }
    a[now]=max(0,a[now]-b[now]);
}

int main()
{   long _=1,__=1,n,i,x,y;
    for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
        memset(fa,0,sizeof(fa));
        for(i=1;i<=n;i++)
        	mp[i].clear();
        scanf("%ld",&n);
        for(i=1;i<n;i++){
            scanf("%ld%ld",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        for(i=1;i<=n;i++)
            scanf("%lld %lld",&a[i],&b[i]);
        build(1);
        if(a[1])
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}

7.s10的数学题

题意

计算\(\Pi_{i<j}|a_i-a_j|%m\)

题解

cf某场div2的原题,简单来说就是如果出现了两个取模相等的,那么就肯定是0,剩下的暴力解决

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

long a[def];

int main()
{	long _=1,__=1,n,m,i,j,x;
	ll sum;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		scanf("%ld%ld",&n,&m);
		for(i=1;i<=n;i++)
			scanf("%ld",&a[i]);
		if(n>m)
			printf("0\n");
		else{
			sum=1;
			for(i=1;i<=n;i++)
				for(j=i+1;j<=n;j++)
					sum=(sum*abs(a[i]-a[j]))%m;
			printf("%lld\n",sum);
		}
	}
	return 0;
}

8.qw的选择题

题意

考试每题乱选答案,但是答案填错了,填到了下一题的位置,每题有\(a_i\)个选项,问得分期望

题解

3种情况,分情况暴力枚举
1)\(a_i<a_{i+1}\)
得分概率\(=\frac{1}{a_i}*\frac{a_i}{a_{i+1}}\)
2)\(a_i=a_{i+1}\)
得分概率\(=\frac{1}{a_i}\)
3)\(a_i>a_{i+1}\)
得分概率\(=\frac{1}{a_{i+1}}*\frac{a_{i+1}}{a_i}\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

double a[def];

int main()
{	long _=1,__=1,n,i;
	double ans; 
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		scanf("%ld",&n);
		for(i=0;i<n;i++)
			scanf("%lf",&a[i]);
		ans=0;
		for(i=0;i<n;i++)
			if(a[i]<a[(i+1)%n])
				ans+=1/a[i]*(a[i]/a[(i+1)%n]);
			else if(a[i]==a[(i+1)%n])
				ans+=1/a[i];
			else
				ans+=1/a[(i+1)%n]*(a[(i+1)%n]/a[i]);
		printf("%.2lf\n",ans);
	}
	return 0;
}

9.张三的幸福生活

题意

输入n,问从0到n有几个数

题解

按理来说是签到题,但是看看范围知道不简单
写个阉割版高精度就好了(只需要实现+1操作)
(给最后一位+1,然后一位一位往前看是否需要进位)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define ll long long
#define INF ~(1<<31)
#define def 100010
using namespace std;

string deal(string s)
{	long i;
	if(s.length()>=21)
		return "Zhang San will never have girlfriend!";
	s[s.length()-1]++;
	for(i=s.length()-1;i>0;i--)
		if(s[i]>'9'){
			s[i]='0';
			s[i-1]++;
		}
	if(s[0]>'9'){
		s[0]='0';
		s='1'+s;
	}
	return s;
}

int main()
{	long _=1,__=1,i;
	ll maxx=1,n;
	string s;
	for(((1)?scanf("%ld",&_):EOF);_;_--,__++){
		cin>>s;
		cout<<deal(s)<<endl;
	}
	return 0;
}

标签:now,min,max,电子科技,题解,Debug,程序设计,include,define
来源: https://www.cnblogs.com/2017py/p/12733098.html