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

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

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值