2021年5月17日-5月23日ACM学习日志

本周学习:二分法,搜索

二分法:
这周大部分是在做二分法的题目,比起dp,二分法的思路我感觉还是比较好想的,做题的速度和质量都比上周要强,晚上自己做出来一个,就很兴奋,还想再看下一个题,看到ac就感觉很爽,不过也遇到过很懵的时候,就是运行没错,就是没有输出,就很奇怪,我到现在也没搞明白我那个代码错那,就是没有输出,在做题过程中还有一点是,注意数组的大小和froopen提交时的注释,我已经因为这两个wr好几次了,老是忘,一看见运行结果对,就提交,以后要注意点,如果比赛的时候因为这个罚时就后悔死了。老师就说过,第一次就ac的代码肯定是验证了好几遍,然后一提交才可能一次ac的。说一下二分法的基本吧,就比如你有一组数,你要找一个数,当然,你可以遍历一遍,这样肯定能找到那个数,但效率太低,所以就有了二分的思想,先把数排序,这个在某些题中很重要,很重要,很重要,重要的事情说三遍,然后看看要查找的数在分的那一边,就把那一边再二分,再查找,最终找到答案。
当然,有的题他只是二分的思想,可能给你不止一组数组,或者给你一个式子,这时候我们就要简化式子了,把他变成查找一个数的形式。例如vj二分作业上的d题。给出你几组a[i],b[i],c[i],d[i],求出这次组中,有几组是a+b+c+d=0的。这时候就需要我们化简式子了,我们把a[i]和b[j]和一块ab[k],c[i]和d[j]和一块成cd[k], 然后排序,利用两个函数就能解决问题了。

 sum+=upper_bound(cd,cd+n*n,-ab[i])-lower_bound(cd,cd+n*n,-ab[i]);

这两个函数虽然不常用,但是用的时候真的挺好用的,还有STL,下面会说,真的很方便。

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
typedef long long  ll;
#define pi acos(-1)
#define INF 0x7fffffff
#define t() cin>>t; while(t--)
#define mem(x) memset(x,INF,sizeof(x))
#define rep(m,n,h) for(int m=n;m<=h;m++)
#define fo(m,n,h) for(int m=n;m<h;m++)
#define cls(x) memset(x,0,sizeof(x))
const ll maxn=0x7fffffffffffffff;
const int N=5000;
const int mod=1e3+7;
bool f[N];
ll dp[N],a[N],b[N],c[N],d[N],ab[N*N],cd[N*N];
int i,j,k,n,m=0,t;
map<string,int> mp;
int main()
{
    //freopen("C:\\Users\\lenovo\\Desktop\\in.txt","r",stdin);
    std::ios::sync_with_stdio(false);
    cin>>n;
    rep(i,0,n-1)
    cin>>a[i]>>b[i]>>c[i]>>d[i];
    rep(i,0,n-1)
    rep(j,0,n-1)
    {
        ab[i*n+j]=a[i]+b[j];
        cd[i*n+j]=c[i]+d[j];
    }
    sort(ab,ab+n*n);
    sort(cd,cd+n*n);
    ll sum=0;
    for(i=0; i<n*n; i++)
    {
        sum+=upper_bound(cd,cd+n*n,-ab[i])-lower_bound(cd,cd+n*n,-ab[i]);
    }
    cout<<sum<<endl;
    return 0;
}

关于upper_bound 和 lower_bound

upper_bound(begin, end, value);
返回>value的元素的第一个位置。

lower_bound(begin, end, value);
返回>=value的元素的第一个位置。

num[] = {1,2,2,3,4,5};
lower_bound(num, num + 6, 2)为num + 1
upper_bound(num, num + 6, 2)为num + 3

顺便复习一下这两个函数。

再说下一个做题的分享,就是要多用STL,真的很方便,那些函数其实很容易看懂,以前就是想不起来用,这次可尝到甜头了,STL真香,vj二分作业的b题,就是用的map函数,用字符作为下标,上周末做的,本以为自己做二分的题会花费很长时间呢,做题的时候就是突然想到map了,一提交就ac了,花费的时间和写的代码都不长。,题意是如果输入了与之前输入的字符相同的字符,就输出这次字符,然后后面依次加一,如果之前没有,就输出OK。利用map函数很快就出结果。

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
typedef long long  ll;
#define pi acos(-1)
#define INF 0x7fffffff
#define t() cin>>t; while(t--)
#define mem(x) memset(x,INF,sizeof(x))
#define rep(m,n,h) for(int m=n;m<=h;m++)
#define cls(x) memset(x,0,sizeof(x))
const ll maxn=0x7fffffffffffffff;
const int N=1e5+3;
const int mod=1e3+7;
bool f[N];
int dp[N],a[N];
int i,j,k,n,m,t;
map<string,int> mp;
int main()
{
    //freopen("C:\\Users\\lenovo\\Desktop\\in.txt","r",stdin);
    std::ios::sync_with_stdio(false);
    cin>>n;
    string s;
    rep(i,1,n)
    {
        cin>>s;
        if(!mp[s])
            cout<<"OK"<<endl;
        else
        {
            cout<<s<<mp[s]<<endl;
        }
        mp[s]++;
    }

    return 0;
}

STL好用啊!

还有一个近似值的题,这个二分的循环和之前的不一样,但我看了一会就知道大概思路了。vj上的n题,就是结果要求要近似到多少位,老师上课讲的题也有过这样的方法。就像这样

while(r-l>=1e-6)
        {
            double s=0;
            double mid=(r+l)/2;
            rep(i,1,n)
            s+=pow(mid,t-a[i].x+1)*a[i].y;
            if(s<v)
                l=mid;
            else
                r=mid;
        }

因为要求近似,所以要用double,一开始有点变量我给写成int了,就是写int写习惯了,一不留神就写错了。
或者这样写,我自身感觉很妙

   while(1)
        {
            s=0;
            double mid=(r+l)/2;
            rep(i,1,n)
            s+=b[i]*pow(mid,t-a[i]+1);
            if(fabs(s-v)<1e-6)
                break;
            else if(s>v)
                r=mid;
            else
                l=mid;
        }
}

这两种都可以,自己想出来的两种方法,好有成就感。
这个题还有一个非常坑的地方,就是两组测试数据之间有一空行,我一开始真的没注意,结果Presentation Error了好几次,一看题才发现,以后这种事情也要注意一下。

搜索
搜素嘛,这周就是听老师讲课了,自己也就看了看ppt,老师讲的时候也就大概能听懂,真正理解还要多做题才行,现在感觉搜索好像与平时的思考方式也不一样,自己要写int search(int); int print();这两个函数,就感觉以前没这样写过。之后做搜索的题了在仔细写写感受。这次就写写基本的想法吧
深度优先搜索(DFS)用的是递归函数,广度优先搜索(BFS)用的是队列。
他们都是查找一遍后出结果,与直接遍历求结果不同的是,他们是有方向的查找。
DFS是找到一层,然后再找一层进行查找,如果发现没有结果了,就返回上一层,还换一个分支接着找,BDF是找到一层,查询完这一层后,再往下查。

最后
我发现cf上的名字是按照分数分颜色的,就感觉很好玩,而且,最近没有适合我们的比赛,我晚上不想做vj上的题时,我就看看cf上的当天div2的比赛,其实有的题不太难,想一会可能就出来,如果我有思路,我就写一写,明早去教室的时候我补下题,有时候发现,原来可以这样做,感觉这样也能提升自己的思维,这周没有懒惰,每天都在做题,就是晚上ac了一道后,真的很想再做一道,ac的感觉就是让人心情愉悦,加油吧,路还有很长!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值