AcWing
  • 首页
  • 题库
  • 题解
  • 分享
  • 问答
  • 活动
  • 应用
  • 吐槽
  • 登录/注册

mryt笔记

作者: 作者的头像   无味 ,  2021-01-11 12:32:51 ,  阅读 37


1


1.AcWing 104. 货仓选址

知识点:绝对值不等式

拓展:

1.1AcWing 3167. 星星还是树


2.AcWing 898. 数字三角形

知识点:简单dp–数字三角形模型

拓展:

2.1AcWing 1015. 摘花生
2.2AcWing 1027. 方格取数
2.3AcWing 382. K取方格数


3.AcWing 756. 蛇形矩阵

知识点:网格图的向量遍历技巧

这个题之前在语法基础课里做过,直接上代码吧:

#include<iostream>
using namespace std;
int st[110][110];
int num[110][110];
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int main()
{
    int n,m;
    cin>>n>>m;

    int x=1,y=1,z=0;
    for(int i=1;i<=n*m;++i)
    {
        num[x][y]=i;
        st[x][y]=1;

        int x1=x+dx[z%4],y1=y+dy[z%4];//这个z%4是个值得思考的地方,有点东西!!!!!
        if(x1>n||x1<1||y1>m||y1<1||st[x1][y1]==1) z++;
        x+=dx[z%4];y+=dy[z%4];
    }

    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
            cout<<num[i][j]<<" ";

        cout<<endl;
    }
    return 0;
}

其实不用设置数组st[].因为数组num[]是全局变量,所以只要num[]中的数值不为零,就表示这个已经填过数了,要进行转向。

#include<iostream>
using namespace std;
int n,m;
int num[100][100];
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};//涉及到这种循环转换的时候一定要按照下标从0开始!!!
int main()
{
    cin>>n>>m;

    int x=0,y=0,z=0;
    for(int i=1;i<=m*n;++i)
    {
        num[x][y]=i;

        if(x+dx[z%4]==n||y+dy[z%4]==m||y+dy[z%4]<0||num[x+dx[z%4]][y+dy[z%4]]!=0)
            z++;

        x=x+dx[z%4];y=y+dy[z%4];

    }
    for(int i=0;i<n;++i){
        for(int j=0;j<m;++j)
            cout<<num[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}

这个题最核心的地方一个是dx[]和dy[]数组,另一个地方就是变量z取余进行变向。
这两个地方(可以归结为偏移量技巧)是可以用在其他题上边的.
y总代码:

#include<iostream>
using namespace std;

int res[100][100];

int main()
{
    int n, m;
    cin >> n >> m;

    int dx[] = {0, 1, 0, -1}, dy[] =  {1, 0, -1, 0};

    for (int x = 0, y = 0, d = 0, k = 1; k <= n * m; ++k)
    {
        res[x][y] = k;
        int a = x + dx[d], b = y + dy[d];
        if(a < 0 || a >= n || b < 0 || b >= m || res[a][b])
        {
            d = (d + 1) % 4;
            a = x + dx[d], b = y + dy[d];
        }
        x = a, y = b;
    }

    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < m; j ++) cout << res[i][j] << " ";
        cout << endl;
    }
    return 0;
}

其他思路: 利用left right top bottom 四个变量来表示这个矩形的边界

#include <iostream>
using namespace std;
const int N = 105;
int a[N][N];
int n, m;
int main() {
    cin >> n >> m;

    int left = 0, right = m - 1, top = 0, bottom = n - 1;
    int k = 1;
    while (left <= right && top <= bottom) {
        for (int i = left ; i <= right; i ++) {
            a[top][i] = k ++;
        }
        for (int i = top + 1; i <= bottom; i ++) {
            a[i][right] = k ++;
        }
        for (int i = right - 1; i >= left && top < bottom; i --) {
            a[bottom][i] = k ++;
        }
        for (int i = bottom - 1; i > top && left < right; i --) {
            a[i][left] = k ++;
        }
        left ++, right --, top ++, bottom --;
    }
    for (int i = 0; i < n; i ++) {
        for (int j = 0; j < m; j ++) {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}

拓展:

3.1AcWing 40. 顺时针打印矩阵
这个


4.AcWing 1113. 红与黑AcWing 1113. 红与黑

知识点:flood fill算法

拓展:

4.1


5.AcWing 1346. 回文平方

知识点:进制转换

进制转换一直没掌握,看到这个题第一反应是笑了哈哈哈哈,那就在今天把你解决了吧!!!

这个题关键在于:如何将十进制数转换成B进制数;另一个是如何判断回文数.

我们在判断回文数的时候对字符串的处理是最简单的,那么这个题在进制转换时就可以转换成字符串.
先来解决十进制转换成R进制:
核心代码:

char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J'};//注意c[]数组的每个值都要加上单引号,包括数字也要加上单引号.
string s;//存储转换后的R进数(注意是逆序!!)
while(j)//j表示十进制数
{
    s+=c[j%b];//b表示B进制
    j=j/b;

}//此时s存储的转换后的R进制数是逆序的!!!要给倒过来
for(int left=0,right=s.size()-1;left<right;left++,right--)
    swap(s[left],s[right]);

拿这个题来检验一下上面代码的正确性 HDU 2031.二进制转换

#include<iostream>
using namespace std;
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
int main()
{
    int n,r;
    while(cin>>n>>r)
    {
        if(n==0)//对0要进行特判,易错!!!!!!!!
        {
            cout<<0<<endl;
            continue;
        }

        string s;
        bool st=false;
        if(n<0)
        {
            st=true;
            n=0-n;
        }
        while(n)
        {
            s+=c[n%r];
            n=n/r;
        }
        if(st) s+='-';
        for(int l=0,right=s.size()-1;l<right;l++,right--)
            swap(s[l],s[right]);

        cout<<s<<endl;

    }
    return 0;
} 

对回文数的判断就简单了,用双指针

#include<iostream>
using namespace std;
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J'};
int main()
{
    int n;
    cin>>n;

    for(int i=1;i<=300;++i)
    {
        int j=i*i;
        string s;
        while(j)
        {
            s+=c[j%n];
            j=j/n;
        }

        bool st=true;//默认是回文
        for(int left=0,right=s.size()-1;left<right;left++,right--)
            if(s[left]!=s[right])//当有一个字符不是的时候
            {
                st=false;
                break;
            }
        if(st==true)
        {
            //输出的第一个数表示满足平方值转化为 B 进制后是回文数字那个数,由于题干要求这个数是在B进制下数,所以要转换
            int k=i;
            string s1;
            while(k)
            {
                s1+=c[k%n];
                k=k/n;
            }
            for(int left=0,right=s1.size()-1;left<right;left++,right--)
                swap(s1[left],s1[right]);

             cout<<s1<<" "<<s<<endl;
        }

    }
    return 0;
}

精简一下:

#include<iostream>
using namespace std;
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J'};
string transform(int num,int b)
{
    string s;
    while(num)
    {
        s+=c[num%b];
        num=num/b;
    }
    for(int left=0,right=s.size()-1;left<right;left++,right--)
        swap(s[left],s[right]);
    return s;
}
bool check(string s)
{
    bool st=true;//默认是回文
    for(int left=0,right=s.size()-1;left<right;left++,right--)
        if(s[left]!=s[right])//当有一个字符不是的时候
            return false;

    return true;
}
int main()
{
    int b;
    cin>>b;

    for(int n=1;n<=300;++n)
    {
        string s1;
        s1=transform(n*n,b);//进制转换

        bool st=check(s1);
        if(st==true)
        {
            //输出的第一个数表示满足平方值转化为 B 进制后是回文数字那个数由于题干要求这个数是在B进制下的数,所以要转换
            string s2;
            s2=transform(n,b);

            cout<<s2<<" "<<s1<<endl;
        }
    }
    return 0;
}

注意c[]数组的每个值都要加上单引号包括数字也要加上单引号.

出事了:上面HDU那个题,在SDUT( SDUT1252进制转换 )上有个一摸一样的,并且显示来源是HDU,但是提交上边的代码一直是WA,这是怎么回事呢?
原来0在任何进制下都是0,但是按照上边的写法输入0,什么都不输出,因为字符串s为空.
所以要特判一下,HDU后台应该没有0这个样例.

#include<iostream>
using namespace std;
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
int main()
{
    int n,r;
    while(cin>>n>>r)
    {
        if(n==0)//对0要进行特判,易错!!!!!!!!
        {
            cout<<0<<endl;
            continue;
        }

        string s;
        bool st=false;
        if(n<0)
        {
            st=true;
            n=0-n;
        }
        while(n)
        {
            s+=c[n%r];
            n=n/r;
        }
        if(st) s+='-';
        for(int l=0,right=s.size()-1;l<right;l++,right--)
            swap(s[l],s[right]);

        cout<<s<<endl;

    }
    return 0;
} 

由于AcWing1346.回文平方这个题从1开始,所以不需要特判!!!

对0要进行特判,易错易忘!!!!!!!!!!!!

拓展:

5.1 AcWing124. 数的进制转换
上面的transform()函数只是针对于十进制转成N进制,那么M进制转成N进制怎么转呢?

5.2 SDUT4609 小数进制转换


6.AcWing 680. 剪绳子

知识点:浮点数二分

拓展


7.AcWing 1227. 分巧克力

知识点:整数二分

QQ截图20210115205614.jpg

#include<iostream>
using namespace std;
int n,k;
int h[100005],w[100005];
int main()
{
    cin>>n>>k;
    int max=0;
    for(int i=1;i<=n;++i)
    {
        cin>>h[i]>>w[i];
        if(min(h[i],w[i])>max) max=min(h[i],w[i]);
    }//得到一个从全局来看,可以切出的最大边长

    for(int i=max;i>=1;--i)//将最大边长从大到小开始遍历
    {
        int cnt=0;//统计N块巧克力可以切出来多少i*i的巧克力
        for(int j=1;j<=n;++j)
            cnt+=(h[j]/i)*(w[j]/i);

        if(cnt>=k)//当cnt>k时,表示切出来的i*i的巧克力可以满足K个小朋友,输出
        {
            cout<<i;
            break;
        }
    }
    return 0;
}

QQ截图20210115210925.jpg
说明整体思路是没错的,要进行优化.
上面代码的复杂度是0($n^2$)的.而n<=$10^5$,肯定是超时的

这个题要想不超时,是要用二分的.


拓展:

0 评论

你确定删除吗?

© 2018-2021 AcWing 版权所有  |  京ICP备17053197号-1
联系我们  |  常见问题
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息