我是靠谱客的博主 炙热吐司,最近开发中收集的这篇文章主要介绍ACM解题经验,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 胆大心细,大巧不工

  • 读万卷书不如行万里路,行万里路不如名师指路。

  • 天上飞的理念,必有落地的实现。

  • 正常学习:理论,实操,总结

  • 快速学习:用中学,学中用

  • 大事着眼,小事着手

  • 先纵观全局,再从细微之处入手。如果一开始就只关注细节,很有可能就钻牛角尖了。

  • 如果仅从微观的视角关注每一个单独的点,可能就会因为看不到整体而迷失了方向。

首先,对于正规题目一般都有规律,不会出现你要考虑所有细节的问题,若考虑全部细节则会遗漏细节,所以贪心算法从局部推最优基本是万能的,当从全局问题考虑出现很多问题时,或者有很多细节要解决时一般是推理错误,因为一般正规ACM代码50行左右,因此全局推理一般不适用,学会使用贪心很重要
结论:暴力深搜解决所有题目细节的方式不可取,结果一般超时,且代码太长,所以有个小窍门代码越短准确率越高

  1. 首先可以观察数据存储大小来判断是否使用并查集等需要倍数n的算法,并且通过数据范围还可以判断是否使用打表的方法
  2. ACM竞赛中for循环最多1000000~100000000,八次方时就很悬了,除非循环体特别简单
  3. 数值计算时先乘后除,缩小精度差。
  4. 定义数组是五次方以内可以在函数内定义,大于五次方就要在函数外定义
  5. 一般通过率较高的题目都是比较简单的贪心找规律,一定不要考虑全部细节贪心找规律就行就行
  6. 记忆化搜索中记忆的数据应该是准确,充分的,且不可更新的
    蓝桥杯例题
    个人错误记忆化代码和标准代码对比
    正确代码记忆化时将每个点的全部可到达的数量进行赋值,而我将可到达路径进行赋值导致每个点的赋值不够充分,从而会使答案偏小。
//正确代码
int dfs(int x, int y) // 搜索点 (x, y),并返回从点 (x, y) 开始,能到点 (n, m) 的路径数量
{
    if (x & 1 || y & 1)
    {
        if (f[x][y]) return f[x][y];         // 如果该点已经被搜索过,那么不再处理
        // 否则说明没搜索过,需要搜索一遍
        if (x < n) f[x][y] += dfs(x + 1, y);
        if (y < m) f[x][y] += dfs(x, y + 1);
    }
    return f[x][y]; // 最后返回 f[x][y] 即可。如果 x, y 都是偶数,那么 f[x][y] 就没被处理过,必然为 0,可以不特判。
}
//个人错误代码。
void def(long long x,long long y){
	if(a[x][y]){
		for(int i=0;i<t;i++){
			a[b[i][0]][b[i][1]]=a[x][y];
		}
		sum+=a[x][y];
		return;
	}
	if(x==n&&y==m){
		for(int i=0;i<t;i++){
			a[b[i][0]][b[i][1]]++;
//			if(a[b[i][0]][b[i][1]]>1)cout<<a[b[i][0]][b[i][1]]<<endl;
		}
		sum++;
		return; 
	}
	x+=1;
	if((x%2!=0||y%2!=0)&&x<=n&&y<=m){
		b[t][0]=x;
		b[t++][1]=y;
		def(x,y);
		t--;
	}
	x-=1;
	y+=1;
	if((x%2!=0||y%2!=0)&&x<=n&&y<=m){
		b[t][0]=x;
		b[t++][1]=y;
		def(x,y);
		t--;
	}
	y-=1;
}
  1. 注意逆向思维很重要,题目会引导你向错误的方向考虑,因此一定要从反方向考虑问题,比如数学公式就要进一步换算,而给定的规律也要使用相反的顺序实现
    举例:
    我的又臭又长的代码(因为完全按照给定规律的方向考虑)
#include<iostream>
using namespace std;
long long ma=1000000007;
int main(){
	long long n;
	cin>>n;
	string s;
	cin>>s;
	long long ma1=0;
	long long sum=0,sum1=0;
	for(long long i=0;i<s.length();i++){
		if(s[i]=='1'){
			ma1=i+1;
		 }
		 if(ma1>0){
			sum+=(ma1);
			sum%=ma;
			sum1+=(i+1)*(ma1)%ma;
			sum1%=ma;
		}
	}
	long long count=0;
	ma1=0;
	for(long long i=0;i<s.length();i++){
		count+=sum1;
		count%=ma;
		sum1-=sum;
        if(s[i]=='1'){
//        	cout<<i+1<<endl;
		for(long long j=i+1;j<s.length();j++){
			if(s[j]=='1')break;
			else {
				sum-=i+1;
				sum1-=(j-i)*(i+1);
			}
			if(sum<0)sum+=ma;
			if(sum1<0)sum1+=ma;
		}
        	sum-=i+1;
        	if(sum<0)sum+=ma;
		}
		if(sum1<0)sum1+=ma;
	}
	cout<<count<<endl;
	return 0;
} 

题解(差距显而易见)

#include<iostream>
#include<string.h>
using namespace std;
typedef long long ll;
ll mod=1000000007;
ll geshu(ll n){
	return (n*(n+1)/2)%mod; //n*(n+1)肯定是偶数
}
int main(){
	int n;
	ll ans=0;
	cin>>n;
	string s;
	cin>>s;
	int cnt=0,tmp;
	for(int i=0;i<s.length();i++){
		
		tmp=s[i]-'0';
		if(tmp){
			cnt=i+1;//cnt记录最右边1的位置
		}
		//cout<<"cishi tmp:"<<tmp<<"cishi cnt:"<<cnt<<endl;
		ans=(ans+((geshu(i+1)-geshu(i+1-cnt))*cnt%mod))%mod;
	}
	cout<<ans<<endl; 
}

字典序
len(a)>len(b)则a>b
if(a[i]>b[i])则a>b

输出多个情况的时候,多半是需要按照字典序最小进行输出,这样答案唯一,且后台判断也相对简单。

最后

以上就是炙热吐司为你收集整理的ACM解题经验的全部内容,希望文章能够帮你解决ACM解题经验所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部