美文网首页
CSP入门的三道题(M1

CSP入门的三道题(M1

作者: 大家好我是阿凉 | 来源:发表于2020-03-17 17:40 被阅读0次

1.模拟转圈圈:
题面:一个字符串和一个转盘,一开始转盘指向a,问转盘指向完整个字符串的最小代价是多少。
字符串均为小写字母。
Input:
hzet
Output:
31

这道题现实意义上很简单,就是直接模拟一个一个走就行。因为是一个字母序的环,所以直接取min(字母序距离,26-字母序距离)。换言之直接用ascii计算也可

#include<iostream>
#include<string>
#include<string.h>
#include<cstring>
using namespace std;
int geeet(int a)
{
    if(a>=0)
//
    {
        return a;
    }
    else
    {
        return a+26;
    }
}
int min(int a,int b)
{
    if(a>b)
    {
        return b;
    }
    else
    {
        return a;
    }
    return 0;
}
int main()
{
    
    string x;
    cin>>x;
    int sum=min(geeet(x[0]-'a'),geeet('a'-x[0]));
    int a=x.length();
    for(int i=0;i<a-1;i++)
    {
        sum+=min(geeet(x[i]-x[i+1]),geeet(x[i+1]-x[i]));
    }
    cout<<sum<<endl;
    return 0;
}

2.依旧模拟:


image.png

题面有些不太清楚。。
需要注意的是:1.给出了两种购买策略,一天可以用很多次这两个其中之一的策略 2.购物券只能留一天。。
所以就很清楚了 ,简单的模拟,每天看看前一天有没有购物券,先用了(不能用直接return false),再看看是奇是偶。能不能给明天留购物券
直接上代码了QAQ

#include<iostream>
using namespace std;
int main()
{
    int n;
    bool jieguo=true;
    cin>>n;
    int a[100000+10];
    int juan=0;
    bool havejuan=0;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    for(int i=0;i<n;i++)
    {
        if(havejuan)
        {
            if(juan>a[i])
            {
                jieguo=false;
                break;
            }
            else if(juan==a[i])
            {
                juan=0;
                havejuan=0;
                continue;
            }
            else
            {
                a[i]=a[i]-juan;
                havejuan=0;
            }
        }
        if(a[i]%2==0)
        {
            continue;
        }
        if(a[i]%2==1)
        {
            havejuan=1;
            juan=1;
        }
    }
    if(havejuan)
    {
        jieguo=false;
    }
    if(!jieguo)
    {
        cout<<"NO"<<endl;
    }
    else
    {
        cout<<"YES"<<endl;
    }
    return 0;
}

3.一道dfs+剪支的问题


image.png
image.png

首先看……思路。大概看上去题面应该是类似一个二叉树的结构。每一个节点造成一定的影响之后会分裂出两个其他的节点 。两个分裂出来的起点就是该点的终点,而且左右各转了45度。

那基本的思路就有了,定义一个射线类,规定走多长,方向,起点,dfs去对每次分裂的每条射线进行模拟。先确定数据范围,发现300*300的访问数据就够了,先重置为0访问过就标记该点为1,然后记录每次分裂出来的射线加入队列。从队列顶部弹出一个然后先走一段延续的距离再分裂……。
开始码!

#include<iostream>
#include<queue>
#include<string>
#include<string.h>
#include<cstring>
#include<cmath>
using namespace std;
int vis[1000][1000];
int temp=0;
int a[40];
struct dian
{
    int x;
    int y;
    int ts;
    int tb; 
};
int tl,tk;
dian xuanzhuan1[2];
void xuanzhuan(dian p)
{
    xuanzhuan1[0]=p;
    xuanzhuan1[1]=p;
    //0 1 0 -1
    if(p.tb==0)
    {
        xuanzhuan1[0].tb=-1;
        xuanzhuan1[0].ts=p.ts;
        xuanzhuan1[1].tb=1;
        xuanzhuan1[1].ts=p.ts;
    }
    // 1 1 -1 -1
    else if((p.tb==-1&&p.ts==-1)||(p.tb==1&&p.ts==1))
    {
        xuanzhuan1[0].tb=0;
        xuanzhuan1[0].ts=p.ts;
        xuanzhuan1[1].tb=p.ts;
        xuanzhuan1[1].ts=0;
    }
    //1 0 -1 0
    else if(p.ts==0)
    {
        xuanzhuan1[0].tb=p.tb;
        xuanzhuan1[0].ts=-1;
        xuanzhuan1[1].tb=p.tb;
        xuanzhuan1[1].ts=1;
    }
    else
    {
        xuanzhuan1[0].tb=0;
        xuanzhuan1[0].ts=p.ts;
        xuanzhuan1[1].tb=p.tb;
        xuanzhuan1[1].ts=0;
    }
}
void kuozhan(dian p,int i)
{
    if(!vis[p.x+p.tb*i][p.y+p.ts*i])
    {
        vis[p.x+p.tb*i][p.y+p.ts*i]=1;
        temp++;
    }
}
int main()
{
    int n;
    int times=1;
    int yk=1;
    cin>>n;
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    queue<dian> q;
    dian p;
    dian begin;
    tl=0;tk=1;
    begin.x=500;
    begin.y=500;
    begin.tb=0;begin.ts=1;
    q.push(begin);
    while(yk<n)
    {
        p=q.front();
        q.pop();
        for(int i=1;i<=a[yk-1];i++)
        {
            kuozhan(p,i);
        }
        dian pl;
        pl.x=p.x+p.tb*a[yk-1];
        pl.y=p.y+p.ts*a[yk-1];
        xuanzhuan(pl);
        
        q.push(xuanzhuan1[0]);
        q.push(xuanzhuan1[1]);

        times--;
        if(times==0)
        {
            times=pow(2,yk);
            yk++;
        }
    }
    cout<<temp<<endl;
    return 0;
}

不到一会儿就写完了,然后提交……不出意外的发现爆内存了。因为每次往队列里面加入的都是……分裂之后的射线。而数据范围n<=30。巅峰时会有2^30根射线加入队列……肯定会炸内存。

所以就要剪支了,一开始剪支剪得很复杂……思路是不会再造成影响的射线都不加入了(我怀疑这样搞写出来也会炸时间)。
后来仔细的思考后发现,其实对每层重合的射线剪支就行。就是棋盘一共300*300,算上四个方向也就720000,和2^30比起来……抽屉原理会发现重了好多射线。所以加个访问数据再加上一维方向。每一次分裂前重置这个数据,然后分裂的时候记录下来已经有该次分裂产生射线的位置和方向,进行剪支。
改进后的代码

#include<iostream>
#include<queue>
#include<string>
#include<string.h>
#include<cstring>
#include<cmath>
using namespace std;
int vis[310][310];
int jianzhi[300][300][3][3];
int temp = 0;
int a[40];
struct dian
{
    int x;
    int y;
    int ts;
    int tb;
};
int tl, tk;
dian xuanzhuan1[2];
void xuanzhuan(dian p)
{
    xuanzhuan1[0] = p;
    xuanzhuan1[1] = p;
    //0 1 0 -1
    if (p.tb == 0)
    {
        xuanzhuan1[0].tb = -1;
        xuanzhuan1[0].ts = p.ts;
        xuanzhuan1[1].tb = 1;
        xuanzhuan1[1].ts = p.ts;
    }
    // 1 1 -1 -1
    else if ((p.tb == -1 && p.ts == -1) || (p.tb == 1 && p.ts == 1))
    {
        xuanzhuan1[0].tb = 0;
        xuanzhuan1[0].ts = p.ts;
        xuanzhuan1[1].tb = p.ts;
        xuanzhuan1[1].ts = 0;
    }
    //1 0 -1 0
    else if (p.ts == 0)
    {
        xuanzhuan1[0].tb = p.tb;
        xuanzhuan1[0].ts = -1;
        xuanzhuan1[1].tb = p.tb;
        xuanzhuan1[1].ts = 1;
    }
    else
    {
        xuanzhuan1[0].tb = 0;
        xuanzhuan1[0].ts = p.ts;
        xuanzhuan1[1].tb = p.tb;
        xuanzhuan1[1].ts = 0;
    }
}
void kuozhan(dian p, int i)
{
    if (!vis[p.x + p.tb*i][p.y + p.ts*i])
    {
        vis[p.x + p.tb*i][p.y + p.ts*i] = 1;
        jianzhi[p.x][p.y][p.tb+1][p.ts+1];
        temp++;
    }
}
int main()
{
    int n;
    int times = 1;
    int yk = 1;
    cin >> n;
    memset(vis, 0, sizeof(vis));
    memset(jianzhi, 0, sizeof(jianzhi));
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    queue<dian> q;
    dian p;
    dian begin;
    tl = 0; tk = 1;
    begin.x = 150;
    begin.y = 150;
    begin.tb = 0; begin.ts = 1;
    q.push(begin);
    while (yk <= n)
    {
        p = q.front();
        q.pop();
        for (int i = 1; i <= a[yk - 1]; i++)
        {
            kuozhan(p, i);
        }
        dian pl;
        pl.x = p.x + p.tb*a[yk - 1];
        pl.y = p.y + p.ts*a[yk - 1];
        pl.tb = p.tb;
        pl.ts = p.ts;
        xuanzhuan(pl);
        if(!jianzhi[xuanzhuan1[0].x][xuanzhuan1[0].y][xuanzhuan1[0].tb+1][xuanzhuan1[0].ts+1])
        {
            q.push(xuanzhuan1[0]);
        }
        if(!jianzhi[xuanzhuan1[1].x][xuanzhuan1[1].y][xuanzhuan1[1].tb+1][xuanzhuan1[1].ts+1])
        {
            q.push(xuanzhuan1[1]);
        }
        times--;
        if (times == 0)
        {
            times = pow(2, yk);
            memset(jianzhi, 0, sizeof(jianzhi));
            yk++;
        }
    }
    cout << temp << endl;
    return 0;
}

在炸时间和炸内存的边缘,咳咳,完美的过 了

相关文章

  • CSP入门的三道题(M1

    1.模拟转圈圈:题面:一个字符串和一个转盘,一开始转盘指向a,问转盘指向完整个字符串的最小代价是多少。字符串均为小...

  • XSS--CSP绕过【firefox和chrome】和data:

    最近做一道关于XSS的CTF题目,用到了data://协议触发XSS,并且需要绕过带nonce的CSP策略。由于题...

  • C++入门必做题 题目 共76道题 绝对收藏

    C++入门必做题 题目 共76道题 以下是C++入门必做题所有题目,共76道题 关于字体显示的说明: 由于字体格式...

  • 关于java异常try catch finally的一道题

    这两天,有人咨询我一道关于java基础的题,具体代码如下: private static int m1() { i...

  • 湮灭的星系 062 血战怪兽

    “5000CSP。” “嘿嘿,杀死这东西竟然有CSP奖励,一只5000CSP?还是三只?” 视网膜前闪过奖励数...

  • 第六十章 CSP的常见问题 - 如何结束CSP会话,CSP会话超

    第六十章 CSP的常见问题 - 如何结束CSP会话,CSP会话超时 如何结束CSP会话? 若要结束CSP会话,请在...

  • 三道题

    成年人的生活就是不断的解决各种问题,俗话说,三个女人一台戏,我家有四个女人,尤其是两个小的,一个十岁,一个三岁,只...

  • 三道题

    今天我在课上做了三道题,错了一道,所以这三道题让我印象非常深刻。 第一道题x的绝对值等于7,y的绝对值等于5,且x...

  • Luogu P5735 距离函数

    题面 这只是道水水的入门题。 平面直角坐标系中两点间距离为所以三角形的周长就是 在比赛中这道题的测试数据仿佛更改过...

  • Go基础——channel

    CSP 要想理解 channel 要先知道 CSP 模型。CSP 是 Communicating Sequenti...

网友评论

      本文标题:CSP入门的三道题(M1

      本文链接:https://www.haomeiwen.com/subject/rtatyhtx.html