2021-03-27

标题ACM第三周,渐入佳境

下面是最近cf的A题,很可惜,wrong answer了。第一次参加比赛,或多或少有点怯场。两个小时,真的是很快呢。其实挺遗憾的,一共有五个测试样例,前四个样例比较顺利,而
而最后一个,总是乱七八糟的一串数字。我知道,最后一个测试样例数量级很大 10的12次方。对于我的错误,不出意外,应该是数据类型出了差错。然后我开始调试。最终以失败告终。下面是我当时写的代码。

#include<iostream>
using namespace std;
int main()
{
    int N;
    long long a[10001];
    scanf("%d",&N);
    for(int j=1; j<=N; j++)
    {  long long m,n,t,s;
        scanf("%d%d%d",&n,&m,&t);
        int p,q;
        p=(t+n-1)/n;
        q=t%n;
        if(q==0) q=n;
        s=m*(q-1)+p;
        a[j]=s;
    };
    for(int i=1; i<=N; i++) {
        printf("%d\n",a[i]);
    };
}

比赛之后,讨论了一下,发现问题出在了数组这里。emmmm。其实到现在我还没彻底明白。呃……
下面是经过略微修改后的程序代码。来看一下吧。

#include<iostream>
using namespace std;

int main()
{
    int N;    
    scanf("%d",&N);
    for(int j=1; j<=N; j++)
    {   long long m,n,t,s;
        scanf("%lld%lld%lld",&n,&m,&t);
        int p,q;
        p=(t+n-1)/n;
        q=t%n;
        if(q==0) q=n;
        s=m*(q-1)+p;
        printf("%lld\n",s);
    };
}

因为上一周没怎么做题,也没怎么总结,这周就来个新的。
按类型总结一下

标题单纯的排序问题

最近做的最简单的一道题,贪心算法X-X。这还是我第一次代码写一遍就AC的,超开心。这道题很多人都说是一道水题,从一种角度来说,确实是这样,毕竟简单。但是,从另一种角度看,这道题是一道具有雏形意义的题。
题目大意是岛上分多个小组,进行投票,每个组超过一半的人投同意,则这个组同意,岛上超过一半的组是同意,则最终才能通过。问,最少多少人投同意票,才能决策才能通过。

解题思路:
先进行第一次排序,按每个小组的人数从小到大排,因为有奇数个小组,只有前(n+1)/2个小组同意,则最终决策通过。每个小组有奇数个人,只要每个小组有(n+1)/2人同意,则小组即为同意票。
代码如下:
这个虽然并不多高级,但还是能正常运行了呢。

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n,a[10001];
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int sum=0;

    for(int i=1; i<=(n+1)/2; i++)
    {
        sum+=(a[i]+1)/2;
    }
    printf("%d\n",sum);
    return 0;
}

标题逻辑思考问题

(我也不知道叫什么名,自己起的)
贪心算法A-A,农场奶牛噪音的问题。这道题我交了好多遍,就是AC不了,但是我感觉没有错误的地方(当然了,可能是我没看出来,或是说还没有想到)。我这样做甚至没用到排序(真是震惊)。

题目大意:
奶牛的音量必须大于距离时,奶牛才可以相互交流。给定奶牛的位置,问音量至少是多少,所有奶牛能一起交流。

解题思路:
是用两个循环,将输入的数据从前往后依次与这个数后面的数做差,取绝对值乘2,再用第二个数与后面的数做差取绝对值乘2,以此类推,将音量相加,即为所有奶牛相互交流时的最低音量。下面是我一直不能AC但结果没有问题的代码:这个我只写了单次运行的,不能多结果输出。

#include<iostream>
using namespace std;

int main()
{
    int N,a[10000],s=0;
    cin>>N;
    for(int i=1; i<=N; i++)
    {
        cin>>a[i];
    }
    for(int i=1; i<=N; i++)
    {   for(int j=i+1; j<=N; j++)
        {
            s+=abs(a[i]-a[j]);
        }
    }
    cout<<2*s<<endl;
}

事实上,我很怀疑,这个真的不一定对,可是有时那么的让我找不出破绽。
然后,下面是我get的别人的题解。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
    int n;
    long long int a[10010];
    long long int c=0;
    cin>>n;
    for(int i=0; i<n; ++i)
        cin>>a[i];
    sort(a,a+n);
    for(int i=1; i<n; i++)
    {
        c+=(a[i]-a[i-1])*i*(n-i)*2;
    }
    cout<<c;
    return 0;
}

区间调度

这个是我最近做的最多的一类题了吧。我比较喜欢的是海岛雷达个数的问题。这个问题和数学结合,刚开始做,忽然有点懵,但是只运用比较简单的数学问题,结合贪心算法,还是比较简单思考解答的。
题目大意:
在陆地上安装雷达,使所有海盗都可以被探测到,给定海盗位置和雷达的辐射范围,问至少安装多少个雷达才能将所有海岛覆盖信号。
解题思路:
在陆地上安装,显然,安装在海岸线上可以覆盖到的海岛数目最多。以海岸线为x轴,海岛坐标为y轴,以海岛坐标为原点,雷达辐射范围为半径,做圆,截x轴一个范围,即为安装雷达该岛可以接收到信号的范围。确定每个海岛与x轴的两个交点之后,以每个区间的左端点为基准排序。如果这一个区间与下一个区间有交集,则取这个交集为新的区间,用该区间与下一个区间作比较,如果有交集,继续这一操作,如果没有,则雷达数量加一。用没有交集的区间作为新的基准区间,重复上述操作。最终得出雷达数量的最小值。
下面,是我出现错误的程序代码。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct D {
    double a,b;
} aa[1001];
struct range {
    double m,n;
} g[1001];
bool cmp(range a,range b) {
    return a.m<b.m;
}
int main()
{
    int n,r,s=0;
    while(scanf("%d  %d",&n,&r)) {
        for(int i=1; i<=n; i++)
        {   scanf("%d%d",&aa[i].a,&aa[i].b);
            g[i]. m=aa[i]. a-sqrt(r*r-aa[i].b*aa[i].b);
            g[i]. n=aa[i]. a+sqrt(r*r-aa[i].b*aa[i].b);
            sort(g,g+n,cmp);
            for(int j=2,x=aa[1].b; j<=n; j++)
            {   if(x>=aa[j].a)continue;
                s+=1;
                x=aa[j].b;
            }
        }
        printf("%d",s);
    }
}

这个错误主要是我没有确定下一个区间的右端在上个区间端点的哪边。我默认为后区间的右端点值比上一区间右端点值大了。这一般就是我比较容易犯错的地方。
下面是我get的别人的题解,我知道是汗颜了d(ŐдŐ๑)。
这个程序运用了比较多的我不会用的知识(有些学过,但是我还没用过,那就先看看别人怎么用的吧)。就是因为不会才要学嘛。

#include <iostream>
#include <cmath>
#include <string.h>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <utility>
using namespace std;

const int maxn = 1000 + 5;

int main()
{
    int n, k = 1;
    double d;
    while (scanf("%d%lf", &n, &d) && (n != 0 || d != 0)) {
        vector<pair<double, double> > st;
        bool vis[maxn];
        memset(vis, false, sizeof(vis));
        double x, y, l, r;
        bool flag = false;
        for (int i = 0; i < n; ++i) {
            scanf("%lf%lf", &x, &y);
            if (y > d)
                flag = true;
            if (!flag) {
                l = x - sqrt(d * d - y * y);
                r = x + sqrt(d * d - y * y);
                st.push_back(make_pair(r, l));
            }
        }
        if (flag) {
            printf("Case %d: -1\n", k++);
            continue;
        }
        int count = 0;
        sort(st.begin(), st.end());
        memset(vis, false, sizeof(vis));
        for (int i = 0; i < st.size(); ++i) {
            if (vis[i])
                continue;
            ++count;
            r = st[i].first;
            vis[i] = true;
            for (int j = i + 1; j < st.size(); ++j)
                if (st[j].second <= r)
                    vis[j] = true;
        }
        printf("Case %d: %d\n", k++, count);
    }
}

我也学习了一下这个,哦,我的天哪,真的好多没见过,没用过的东西呀。
临时抱佛脚的去get一点新知识。
###memset的相关知识:
该函数对数组操作时只能用于数组的置0或-1,其他值无效(出现错误值)。
1.初始化整型数组:memset(iarr,0,sizeof(iarr)); 或者 memset(iarr,- 1, sizeof(iarr));
2. 初始化字符串:memset(str,‘\0’,sizeof(str));
3. 我的理解:
memset(a,0,3);就是将a后面的元素初始化为0。

在之前学STL时简单地学过了一点动态数组的相关知识,但是还没用过,这个对于我来说也是个例子吧。get到了。

标题效率、性价比问题

这个就是类似于背包问题,要考虑效率,或者是考虑性价比。
老鼠和猫换食物的问题,我感觉问题描述还挺有意思的。
题目大意:
FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain.
问他最多可以换的多少他喜欢的食物呢?
思路就非常简单了,就是按最高换性价比换。最高性价比的房间换完之后,依次从高到低换剩下的性价比的食物。
程序代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct Node {
    double j,f;
    double price;
};
struct Node node[100007];

int cmp(struct Node a,struct Node b)
{
    return a.price>b.price;
}
int main()
{
    int m,n;
    while(scanf("%d%d",&n,&m)!=EOF&&m!=-1&&n!=-1)
    {
        double s=0;
        for(int i=0; i<m; i++)
        {
            scanf("%lf%lf",&node[i].j,&node[i].f);
            node[i].price=node[i].j/node[i].f;
        }
        sort(node,node+m,cmp);
        for(int i=0; i<m; i++)
        {
            if(n>node[i].f)
            {
                s+=node[i].j;
                n-=node[i].f;
            }
            else
            {
                s+=node[i].price*n;
                break;
            }
        }
        printf("%.3lf\n",s);
    }
    return 0;
}

这个程序是我跟着别人的题解改出来的,我没改的程序真的,emmmm,还要提高才行。就不看那个了。(_😉

总结:对于我来说,这周是全新的一周。因为上一周确实没怎么做题,然后也是因为比较恐惧吧,就不敢尝试。然后这周因为作业时间也快截止了嘛,然后就比较着急,顾不了那么多了,什么恐惧不恐惧的,在忙碌的时候都忘了。然后就有两三天的时间吧,非常疯狂的做题,上课走神想题,下课写代码做题,当然了,这不是一个很好的习惯,上课就应该好好听课(_😉。啊,因为作业真的要做不完了。

当然了,这两天做的题挺多的,然后其实我自己写的题很多都AC不了,有时候甚至输出样例中都有的数据都会出现差错。有时候我真的想不出来了。哭死了。然后就会去看看别人的题解。怎么说呢?别人的题解中有很多都是我没有学过的,或者说学过但没用过的,也会去查一些新的知识,学一下。

我非常震惊,好久没有见过这样的自己了。题目很多是做出来的,有很多是没做出来的。有的也看过人家的题解,有的也确实是自己绞尽脑汁想出来的。我挺开心,至少努力了。还有就是,我们班选课的人数比较多嘛,上自习了,有时间我就会问他们,觉得这种状态才像大学嘛。
因为这两天提交的题目有点多,还不知道老师算不算分,不管怎么样,我对于这两天的疯狂与忙碌,表示肯定。

对我来说,因为我选课了嘛,本来就更应该更加重视这门课程的学习,其实从这一周开始才算是我的一个小小的蜕变吧!真正的了解了ACM这堂课,真正把时间给了这门课程。我知道我自己的代码能力很弱,其实,以老师之前说的要求来说,是要被劝退的,可是我还是毅然决然的选择了。不想给自己留后路,不想荒废的大学的时光,不想未来叹息人生。

但是和身边的朋友们的差距还是很明显的,会失落,会羞愧,会想放弃,说什么“挂就挂了吧”,但是还是要鼓起勇气,继续走下去。在这里,再多给自己一点勇气吧(好矫情呀)。
总而言之,就是自己很弱,要一点一点的补,不可能一下子就赶上啊。就算比赛出不了题,vjudge上的题目AC不了,那还是要一点一点学呀。你选这门课本来就是为了学更多知识,积累更多经验,不断提升自己,不断升华自己的。相对于他们来说,自己就是弱呀,就是比不上呀,可是还有机会啊!选这门课不就是为了更接近他们吗,不就是为了变得更优秀吗?现在比不上,也不算什么,不是吗?不断积累,不断升华,真正的提升自己才是最重要的呀。我知道其实还挺担心会挂科这个事儿的,可是就像老师说的,只要你好好学,想挂科都难。即使在这开始的几周中,你得不到成绩,但继续努力,一定是没有错的,几周过后拿到成绩不也是手到擒来的事么。
好了,这周就到这里了。希望下一站有新蜕变,新成长!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值