2021.5.29比赛补题报告三角函数+模拟+前缀和

博客围绕ACM竞赛相关内容展开,包含“翻滚吧硬币”和“生命的游戏”两道题的题解,前者是数学题,通过大圆圆心走过距离除以周长求解;后者是模拟题,需按要求模拟。还介绍了新的AUPC赛制,以及Alice解决题目最少罚时问题,涉及前缀和知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

★★翻滚吧硬币★★
链接:https://ac.nowcoder.com/acm/contest/16520/J

在这里插入图片描述
题解:一道数学题。大圆滚两个小圆时,圈数最少。大圆圆心走过的距离除以大圆周长即为所求。
公式:
在这里插入图片描述
s为滚过的距离,最后s除以大圆周长即可。
代码:

#include<bits/stdc++.h>
using namespace std;
const long double pi=acosl(-1);//圆周率
int T, r[5];
long double ans, a, b, c, x, y;
int main()
{
    cin >> T;
    while (T--) {
        cin >> r[1] >> r[2] >> r[3];
        sort(r + 1, r + 3 + 1);
        a = r[1] + r[2], b = r[1] + r[3], c = r[2] + r[3];
        x = acosl((a * a + b * b - c * c) / (2.0 * a * b));
        y = acosl((a * a + c * c - b * b) / (2.0 * a * c));
        ans = ((pi - x) * b + (pi - y) * c) / (pi * r[3]);
        cout << fixed << setprecision(15) << ans << endl;//cout方式保留后几位小数。
    }
    return 0;
}

★★生命的游戏★★
https://ac.nowcoder.com/acm/contest/16520/C
题解:简单的模拟。只要是模拟题都可以做感觉。。。这种题就是很多不太好想的点组成一个题,需要逐个击破。整体复杂,但是可以做。
根据题目要求模拟就行,它要求干什么就干什么,别怀疑,一般直接暴力就行,不要嫌麻烦,这个题有个点不好想,边缘数据的计算多注意,代码中又标识。

#include<bits/stdc++.h>
#define ll long long
const ll nl=1e5+5;
using namespace std;
ll a[105][105];//输入原始数据
ll aa[105][105];//保存原始数据,方便后续比较
ll p[105][105];//实时记录数据变化
int main(){
	ll t;
	cin>>t;
	ll i,j;
	while(t--){
		ll n,m;
		cin>>n;
		cin>>m;
		ll ans=101;
		for(i=0;i<n;i++){
			for(j=0;j<n;j++){
				cin>>a[i][j];
				p[i][j]=a[i][j];
				aa[i][j]=a[i][j];
			}
		}
		ll k;
		ll flag=0;
		ll f=0;
		for(k=1;k<=m;k++){题目所给的变化周期
			for(i=0;i<n;i++){
				for(j=0;j<n;j++){
					ll sum=0;//记录有多少个1
					if(a[(i-1+n)%n][(j-1+n)%n]==1){//边缘数据需要取模操作,小难点。
						sum++;
					}
					if(a[(i-1+n)%n][(j+n)%n]==1){
						sum++;
					}
					if(a[(i-1+n)%n][(j+1+n)%n]==1){
						sum++;
					}
					if(a[(i+n)%n][(j-1+n)%n]==1){
						sum++;
					}
					if(a[(i+n)%n][(j+1+n)%n]==1){
						sum++;
					}
					if(a[(i+1+n)%n][(j-1+n)%n]==1){
						sum++;
					}
					if(a[(i+1+n)%n][(j+n)%n]==1){
						sum++;
					}
					if(a[(i+1+n)%n][(j+1+n)%n]==1){
						sum++;
					}
					if(p[i][j]==0&&sum==3){
						p[i][j]=1;
					}else if((sum>3||sum<2)&&p[i][j]==1){
						p[i][j]=0;
					}
				}
			} 
		    for(i=0;i<n;i++){
		    	for(j=0;j<n;j++){
		    		if(p[i][j]!=aa[i][j]){
		    			flag=1;
		    			break;
					}
				}
				if(flag==1){
					break;
				}
			}
			if(flag==0){
				ans=k;
				f=1;
				break;
			}else{
				for(i=0;i<n;i++){
					for(j=0;j<n;j++){
						a[i][j]=p[i][j];
					}
				}
			}
			flag=0;
		}
		if(f==0){
			cout<<"NO"<<endl;
		}else{
			cout<<"YES"<<endl;
			cout<<ans<<endl;
		}
	}
} 
★★比赛新机制★★

最近,AllenAllen 教授研发了一种新的比赛机制,这种比赛机制是 ACPCACPC (Asia ; Collegiate ; Programming ; Contest)(AsiaCollegiateProgrammingContest) 赛制的扩展,简称 AUPCAUPC (Asia ; University ; Programming ; Contest)(AsiaUniversityProgrammingContest)。参赛者为个人参赛(即每人一台电脑),且成绩分为两部分,过题数和罚时。每道题目的罚时 ss 与比赛已经开始的时间(按分钟计) aa 以及该题错误的提交次数(不包括编译错误) bb 有关,即 s=a+b \times 20s=a+b×20。
另外,新赛制规定,每位参赛者必须按一定的顺序循环做题,直到解出全部题目或比赛结束。在比赛开始之前,每位参赛者可以任意选择第一个要做的题目和方向:正序或者逆序,但是中途不能跳题或者改变方向。例如,现在有 A,B,C,D,EA,B,C,D,E 五道题目,参赛者可以选择第一个要做的题目 CC,然后按正序 C,D,E,A,BC,D,E,A,B 的顺序做题,或者按逆序 C,B,A,E,DC,B,A,E,D 的顺序做题,而 C,D,B,A,EC,D,B,A,E 或 C,E,A,B,DC,E,A,B,D 都是不被允许的。
AliceAlice 水平非常高,她总是可以做出所有的题目。现在她想知道,如果已知解决每道题需要花费的时间,那么解决 nn 道题的最少罚时是多少。我们认为比赛时间足够 AliceAlice 解决所有题目,在比赛开始的瞬间 AliceAlice 就开始做题并且所有题目都是一次提交便成功通过。
输入描述:
第一行一个整数 T ; (1 \leq T \leq 5 \times 10^{5})T(1≤T≤5×10
5
),表示测试用例的数量。
对于每组测试用例,第一行一个整数 n ; (1 \leq n \leq 5 \times 10^{5})n(1≤n≤5×10
5
),表示题目的数量;

接下来一行 nn 个整数,第 i ; (1 \leq i \leq n)i(1≤i≤n) 个整数 A_{i} ; (1 \leq A_{i} \leq 5 \times 10^{5})A
i

(1≤A
i

≤5×10
5
),表示解决第 ii 道题需要花费的时间(按分钟计)。

对于全部测试用例,保证 \sum n \leq 5 \times 10^5∑n≤5×10
5

输出描述:
对于每组测试用例,输出一行一个整数表示答案。
示例1
输入
2
5
2 1 5 3 4
10
5 9 3 7 8 1 10 4 6 2
输出
36
277
说明
在第一组测试用例中,AliceAlice 按题目编号 2,1,5,4,32,1,5,4,3 的顺序做题,总罚时最少,为 1+3+7+10+15=361+3+7+10+15=36。
在第二组测试用例中,总罚时最少为 5+7+13+17+27+28+36+43+46+55=2775+7+13+17+27+28+36+43+46+55=277。
题解:题目很好理解,就是不会做。
思路:一开始想直接遍历,因为实在没有什么想法。。。结果正如所料,超时了。。然后看了大佬的代码。前缀和问题。
前缀和总结:前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。
定义式 递推式
一维前缀和 b[i]=b[i-1]+a[i]
二维前缀和 b[x][y]=b[x-1][y]+b[x][y-1]-b[x-1][y-1]+a[x][y]

代码如下:

#include<bits/stdc++.h>
#define ll long long
const ll nl=5e5+5;
using namespace std;
#define speed_up ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll a[nl];
ll b[nl];
int main(){
	speed_up;
	ll i,j;
	ll t;
	cin>>t;
	while(t--){
		ll n;
		cin>>n;
		for(i=0;i<=n;i++){
			b[i]=0;
		}//初始化为零
		for(i=1;i<=n;i++){
			cin>>a[i];
		}
		ll sum=0;
		ll ans=0;
		for(i=1;i<=n;i++){
			sum+=a[i]*(n-i+1);//从第一个开始,每一个数分别加了(n-i+1)次
			b[i]=a[i]+b[i-1];//计算到n,看最后的数,不管什么顺序,最后一个数一定相等
		}
		ans=sum;
		for(i=2;i<=n;i++){
			sum+=b[n];//每次改变顺序,都要加一遍所有数
			sum-=n*a[i-1];//减去头上的数*n,因为第一个加了n次
			ans=min(ans,sum);
		}
		reverse(a + 1, a + n + 1);//逆序
		for(i=0;i<=n;i++){
			b[i]=0;
		}
		sum=0;
		for(i=1;i<=n;i++){
			sum+=a[i]*(n-i+1);
			b[i]=a[i]+b[i-1];
		}
		ans=min(ans,sum);
		for(i=2;i<=n;i++){
			sum+=b[n];
			sum-=n*a[i-1];
			ans=min(ans,sum);
		}
		cout<<ans<<endl;
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值