概述
-
胆大心细,大巧不工
-
读万卷书不如行万里路,行万里路不如名师指路。
-
天上飞的理念,必有落地的实现。
-
正常学习:理论,实操,总结
-
快速学习:用中学,学中用
-
大事着眼,小事着手
-
先纵观全局,再从细微之处入手。如果一开始就只关注细节,很有可能就钻牛角尖了。
-
如果仅从微观的视角关注每一个单独的点,可能就会因为看不到整体而迷失了方向。
首先,对于正规题目一般都有规律,不会出现你要考虑所有细节的问题,若考虑全部细节则会遗漏细节,所以贪心算法从局部推最优基本是万能的,当从全局问题考虑出现很多问题时,或者有很多细节要解决时一般是推理错误,因为一般正规ACM代码50行左右,因此全局推理一般不适用,学会使用贪心很重要
结论:暴力深搜解决所有题目细节的方式不可取,结果一般超时,且代码太长,所以有个小窍门代码越短准确率越高
- 首先可以观察数据存储大小来判断是否使用并查集等需要倍数n的算法,并且通过数据范围还可以判断是否使用打表的方法
- ACM竞赛中for循环最多1000000~100000000,八次方时就很悬了,除非循环体特别简单
- 数值计算时先乘后除,缩小精度差。
- 定义数组是五次方以内可以在函数内定义,大于五次方就要在函数外定义
- 一般通过率较高的题目都是比较简单的贪心找规律,一定不要考虑全部细节贪心找规律就行就行
- 记忆化搜索中记忆的数据应该是准确,充分的,且不可更新的
蓝桥杯例题
个人错误记忆化代码和标准代码对比
正确代码记忆化时将每个点的全部可到达的数量进行赋值,而我将可到达路径进行赋值导致每个点的赋值不够充分,从而会使答案偏小。
//正确代码
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;
}
- 注意逆向思维很重要,题目会引导你向错误的方向考虑,因此一定要从反方向考虑问题,比如数学公式就要进一步换算,而给定的规律也要使用相反的顺序实现
举例:
我的又臭又长的代码(因为完全按照给定规律的方向考虑)
#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解题经验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复