3.22~3.23日刷题总结

vj题组刷题

https://vjudge.net/contest/547627#problem/Q

思路:dfs+剪枝,剪枝掉没有必要的操作,降低时间复杂度,

确立r和h的遍历起点,r为递减,而r的大小不能小于0,所以r最小从0开始,h同理。

剪枝操作1:s+2*(N-v)/r>min_s这个时候可以直接返回不必继续搜索,当r取最大的时候,体积为最小,假如假设的最小体积比原来的min_s还要大,就一定不是最优解,没有必要继续搜索下去。

证明:

剪枝操作2:

情况1:if (min_v(m)>N-v)

情况2:if (max_v(r,h,m)<N-v)

这里的min_v的计算是从顶开始制作,以最小半径往下走,计算出的即为最小体积

这里的max_v的计算是从除了已经制作的蛋糕以外的最下面开始,半径为已经相邻层蛋糕的半径-1,此时为最大。

情况1:计算还没有制作的蛋糕的最小体积,假如这个体积大于剩余的体积,那么该情况不需要继续搜索

情况2:同理,计算还没有制作的蛋糕的最大体积,假如小于剩余的体积,也不需要继续搜索了

#include<iostream>
using namespace std;
int N,M;
int min_s=10e8;
int min_v(int m)//计算可以制作的最大体积
{
    int sum=0;
    for (int i=M-m;i>=1;i--)//从最上层开始,以达到体积最小
    {
        sum+=i*i*i;
    }
    return sum;
}
int max_v(int r,int h,int m)//计算可以制作蛋糕的最大体积
{
    int sum=0;
    for (int i=r,j=h;m<=M;i--,j--)//从制作的上一层开始,继续制作以达到最大
    {
        sum+=i*i*j;
        m++;
    }
    return sum;
}
void dfs(int r,int h,int s,int v,int m)
{
    if(v==N&&m==M&&s<min_s)
    {
        min_s=s;//更新答案
        return ;
    }
    if(r==0||s+2*(N-v)/r>min_s)return ;//无必要的搜索剪枝操作1
    if (min_v(m)>N-v)return;//无必要的搜索//剪枝操作2
    if (max_v(r,h,m)<N-v)return;//无必要的搜索
    for (int i=r-1;i>=M-m;i--)//枚举上一层半径
    {
        for (int j=h-1;j>=M-m;j--)//枚举上一层的高
        {
            dfs(i,j,s+2*i*j,v+i*i*j,m+1);//搜索上一层
        }
    }
}
int main()
{
    cin>>N>>M;
    for(int i=M;i*i<=N;i++)//枚举半径
    {
        for(int j=N/(i*i);j>=M;j--)//枚举高度
        {
            int s=i*i+2*i*j;
            int v=i*i*j;
            dfs(i,j,s,v,1);//第一层
        }
    }
    if(min_s==10e8)
    {
        cout<<0<<endl;
    }else cout<<min_s<<endl;
    return 0;
}

https://vjudge.net/contest/547627#problem/P

思路:dfs+回溯,回溯出满足题意的所有回答问题的个数,搜的过程中不断更新结果得到这些结果中的最大值即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#define N 16
using namespace std;
int n,ans;
int book[N];
int a[16][16];
void dfs(int s,int sum,int cost)
{
    ans=max(ans,sum);//更新答案
    if(sum==n)return ;//回答了n个问题
    for(int i=1;i<n;i++)
    {
        if(book[i]==0&&a[s][i]>=cost)//这个题没做过,而且这个题的难度大于等于上一个题的难度
        {
            book[i]=1;//标记为做过
            dfs(i,sum+1,a[s][i]);
            book[i]=0;//回溯
        }
    }
}
int main()
{
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                cin>>a[i][j];
            }
        }
        ans=0;//初始化
        memset(book,0,sizeof(book));//初始化
        dfs(0,1,0);
        book[0]=1;
        cout<<ans<<endl;
    }
}

https://vjudge.net/contest/547627#problem/L

思路:这个题困扰了我太久太久,在纸上模拟了好久循环过程中pos数组的变化,才体会到其中的奥秘,答案不是唯一的,因此设立一个数组,作为模板,与模板进行对比,利用pos数组存储各个序列已经用掉的元素个数。

#include<iostream>
#include<algorithm>
#include<cstring>
#define N 10
using namespace std;
int deep,ans;
char a[N][N];
int n;
char DNA[4]={'A','G','C','T'};
void dfs(int s,int len[])
{
    if(s>deep) return;//大于限制的深度,不用往下搜索 
    int max_=0;
    for(int i=0;i<n;i++)//求预计长度,预计长度为最好的情况下的长度
    {
        int k=strlen(a[i])-len[i];
        max_=max(k,max_);//其中一个最大的即为最理想情况下的长度(满足最长的即可)
    }
    if(max_==0)//预计长度为0,说明匹配完成
    {
        ans=s;
        return;
    }
    if(s+max_>deep)return;//已经构造了的长度+预计长度若大于设置的长度,就返回
    for(int i=0;i<4;i++)//搜DNA数组中的四个元素
    {
        int flag=0;
        int pos[10];
        for(int j=0;j<n;j++)//n个序列的遍历
        {
            if(a[j][len[j]]==DNA[i])//和目标相同
            {
                flag=1;
                pos[j]=len[j]+1;//这一行序列 列+1
            }else
            {
                pos[j]=len[j];//不相等,列不动
            }
        }
        if(flag==1)//出现了相等的情况就继续往下一列搜,如果不相等,就遍历DNA数组的另一个元素,因为要先保证连续性
        {
            dfs(s+1,pos);
        }
        if(ans!=-1) return;
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        deep=0;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            int k=strlen(a[i]);
            deep=max(deep,k);
        }
        ans=-1;
        int pos[10]={0};
        while(1)
        {
            dfs(0,pos);
            if(ans!=-1)//得到结果了
            {
                cout<<ans<<endl;break;
            }
            deep++;
        }
    }
    return 0;
}

cf补题情况:

https://codeforces.com/contest/1807/problem/G1

思路:构造目标数列中元素的顺序,不影响数列的最终结果,因为构造出的元素可以插到任意位置,因此我们先对其进行排序,依次构造过去,这里需要特别判断一下目标数组的数组头,一定要为1,否则无法构造出来,其次判断前缀和和下一个元素的大小,如果这个元素大于这个元素前的前缀和,那么便无法构造。

#include<iostream>
#include<algorithm>
using namespace std;
int a[200005];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        int temp=1;
        bool flag=true;
        sort(a,a+n);
        for(int i=1;i<n;i++)
        {
            if(temp>=a[i])
            {
                temp+=a[i];//计算前缀和
            }else //前缀和小于这个元素,无法构造
            {
                flag=false;break;
            }
        }
        if(a[0]==1)//特别判断数组首元素
        {
            if(flag==true)
            {
                cout<<"YES"<<endl;
            }else 
            {
                cout<<"NO"<<endl;
            }
        }else 
        {
            cout<<"NO"<<endl;
        }
    }
}

https://codeforces.com/contest/1807/problem/G2

思路:hard版数据更大,我们需要开 long long ,时间上的话,hard版的时间刚好在10e9的位置左右,改用scanf输入加快速度,循环遍历搜索到不能构造的情况直接break,减少时间,代码变化不大,可以ac。

#include<iostream>
#include<algorithm>
#define ull unsigned long long
using namespace std;
int T;
bool flag=true;
ull a[200005];
void check()
{
    if(a[0]==1)
    {
        if(flag==true)
        {
            cout<<"YES"<<endl;
        }else 
        {
            cout<<"NO"<<endl;
        }
    }else 
    {
        cout<<"NO"<<endl;
    }
}
void do_()
{
    while(T--)
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            scanf("%llu",&a[i]);
        }
        ull temp=1;
        sort(a,a+n);
        flag=true;
        for(int i=1;i<n;i++)
        {
            if(temp>=a[i])
            {
                temp+=a[i];
            }else 
            {
                flag=false;
                break;//不能构造去跳出循环
            }
        }
        check();
    }
}
int main()
{
    scanf("%d",&T);
    do_();
}

java学习情况:

笔记详情:

总结:vj题组加油刷题,cf补题还差一个。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: CMake是一个跨平台的构建工具,用于自动生成各种编译工具(如Makefile、Visual Studio解决方案等)的配置文件。CMake 3.22.5是CMake的一个特定版本。 CMake 3.22.5是CMake在其开发历史中的一个里程碑版本。它可能包含了一些修复和改进,以提高对各种编程语言(如C、C++、Python等)和平台(如Windows、Linux、macOS等)的支持。 CMake 3.22.5可能包含一些重要的新功能或更新的特性。这些功能可能包括新的模块、插件或命令,以及改进的语法支持。具体来说,CMake 3.22.5可能提供了更简洁、更高效的构建脚本编写方式,使开发人员能够更方便地配置和构建他们的项目。 此外,CMake 3.22.5还可能包含了一些错误修复,以解决之前版本中的一些已知问。这些修复可能包括与特定编译器或操作系统相关的问,或者与特定库或框架的兼容性问有关。 总结而言,CMake 3.22.5是CMake的一个版本,有可能包含了一些新功能、更新的特性和错误修复,以提供更好的跨平台构建支持。使用CMake 3.22.5可以更方便地配置和构建各种项目,并与不同编程语言和操作系统进行更好的集成。 ### 回答2: CMake是一个开源的跨平台自动化构建工具,可以用于简化软件项目的构建过程。它使用名为CMakeLists.txt的配置文件来描述项目构建规则,并生成与目标平台相关的构建脚本(如makefile或Visual Studio项目文件)。 CMake 3.22.5是CMake软件的一个特定版本。升级到CMake 3.22.5可能会带来一些新的功能、改进和修复,以提高构建过程的效率和可靠性。一些可能的变化包括: 1. 新功能:CMake 3.22.5版本可能添加了一些新的功能,如新增了一些命令或模块,以便开发者更方便地配置和构建项目。 2. 改进:该版本可能提供了一些已有功能的改进,以提高构建的性能、可维护性或用户体验。这些改进可能包括bug修复、优化算法或改进命令的用法。 3. 修复:CMake 3.22.5可能解决了之前版本中存在的一些错误或问。这些修复可能涉及到各种方面,如解决已知的bug、兼容性问、性能问等。 使用CMake 3.22.5的好处包括更容易管理项目的依赖关系、更方便地生成构建脚本、更高效地构建项目等。同时,由于CMake是跨平台的,因此可以在不同的操作系统和编译器上使用CMake 3.22.5来构建项目。 总之,CMake 3.22.5是CMake软件的一个特定版本,升级到该版本可能会带来一些新功能、改进和修复,以提高项目的构建过程。 ### 回答3: CMake是一个跨平台的开源构建工具,用于管理软件项目的构建过程。CMake的版本3.22.5是CMake 3系列中的一个版本,它是在2022年5月发布的最新稳定版本。CMake 3.22.5提供了一些功能更新和Bug修复,以提高构建过程的效率和稳定性。 在CMake 3.22.5中,可能包含一些与以前版本不兼容的更改。这些更改可能涉及CMake的语法、模块、命令或功能等方面。因此,在升级到CMake 3.22.5之前,用户应该仔细研究和了解相关文档,以确保项目能够顺利迁移到新版本。 CMake 3.22.5还可能包含一些新的功能和改进。例如,它可能为用户提供了更多的构建选项、编译器支持或库依赖等。这些新功能和改进旨在使开发人员能够更轻松地管理和构建他们的项目。 除了功能更新外,CMake 3.22.5还可能包含一些Bug修复。这些修复旨在解决以前版本中发现的问和错误,以提高CMake在实际使用中的稳定性和可靠性。 总而言之,CMake 3.22.5是CMake构建工具的一个版本,它提供了一些功能更新和Bug修复,以提高软件项目的构建过程效率和稳定性。升级到新版本前,用户应该详细阅读相关文档,并确保其项目能够顺利迁移到新版本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡卡卡卡罗特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值