习题日常第四练

1矩形覆盖(题目链接

这个题一开始我想到的是贪心,按照横向贪和纵向贪,但是想想很明显不对。由于看到洛谷对此题的标签是搜索,我就开始了漫漫搜索路。由于数据太小,所以递归搜索可以不怎么考虑剪枝,但是我还是写了一个在搜索的第一行。搜索目标为每个点,用b数组记录各个矩形的边界,每次递归后将相应的b恢复为递归之前的值,每次递归扩展边界。这个题还有个坑就是每个矩形相互之间不能有边,点重合,所以还要加特判,特判的时候用将俩个矩形的四个角判断,判断是否在对方矩形中。具体代码如下。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll unsigned long long int
const int mod=1e9+7;
using namespace std;
int n,k;
struct node
{
    int x,y;
}a[100];
struct node1
{
    int lx,ly,rx,ry,cnt=0;
}b[10];
int ans=0x3f3f3f;
int check2(int x,int y,int xi,int yi,int xz,int yz)
{
    if(x>=xi&&x<=xz&&y>=yi&&y<=yz)
    {
        return 1;
    }
    else
        return 0;
}
int check()
{
    int i,j;
    for(i=0;i<n;i++)
    {
        int flat=0;
        for(j=1;j<=k;j++)
        {
            if(a[i].x<=b[j].rx&&a[i].x>=b[j].lx&&a[i].y<=b[j].ry&&a[i].y>=b[j].ly)
                flat=1;
        }
        if(flat==0)
            return 0;
    }
    for(i=1;i<=k;i++)
    {
        for(j=i+1;j<=k;j++)
        {
            if(check2(b[i].lx,b[i].ly,b[j].lx,b[j].ly,b[j].rx,b[j].ry))
                return 0;
             if(check2(b[i].rx,b[i].ry,b[j].lx,b[j].ly,b[j].rx,b[j].ry))
                return 0;
             if(check2(b[j].lx,b[j].ly,b[i].lx,b[i].ly,b[i].rx,b[i].ry))
                return 0;
             if(check2(b[j].rx,b[j].ry,b[i].lx,b[i].ly,b[i].rx,b[i].ry))
                return 0;
             if(check2(b[i].rx,b[i].ly,b[j].lx,b[j].ly,b[j].rx,b[j].ry))
                return 0;
             if(check2(b[i].lx,b[i].ry,b[j].lx,b[j].ly,b[j].rx,b[j].ry))
                return 0;
             if(check2(b[j].rx,b[j].ly,b[i].lx,b[i].ly,b[i].rx,b[i].ry))
                return 0;
             if(check2(b[j].lx,b[j].ry,b[i].lx,b[i].ly,b[i].rx,b[i].ry))
                return 0;
        }
    }
    return 1;
}
void dfs(int i,int anp)
{
    if(anp>ans)
        return;
    if(i==n)
    {
         if(check())
         {
             ans=min(ans,anp);
         }
         return;
    }
    node1 pi;
    for(int j=1;j<=k;j++)
    {
        pi=b[j];
        if(b[j].cnt==1)
        {
        if(a[i].x<b[j].lx)
            b[j].lx=a[i].x;
        if(a[i].x>b[j].rx)
            b[j].rx=a[i].x;
        if(a[i].y<b[j].ly)
            b[j].ly=a[i].y;
        if(a[i].y>b[j].ry)
            b[j].ry=a[i].y;
        }
        else
        {
            b[j].lx=a[i].x;
            b[j].rx=a[i].x;
            b[j].ly=a[i].y;
            b[j].ry=a[i].y;
            b[j].cnt=1;
        }
        int s1=(pi.ry-pi.ly)*(pi.rx-pi.lx);
        int s2=(b[j].ry-b[j].ly)*(b[j].rx-b[j].lx);
        dfs(i+1,anp+s2-s1);
        b[j]=pi;
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    ll i=0,j,m=0,sum=0;
    cin>>n>>k;
    for(j=0;j<=k;j++)
    {
        b[j].lx=b[j].rx=b[j].ly=b[j].ry=b[j].cnt=0;
    }
    for(i=0;i<n;i++)
    {
        cin>>a[i].x>>a[i].y;
    }
    dfs(0,0);
    cout<<ans;

  return 0;
}

2过河(题目链接

这个题是个动态规划,因为每一次跳的步长不一样(原来好像做过一道每次跳的步长一样的,用二分),这个题给的整体长度1e9,特别的大,但是有石头的点非常少,跳的步长也不是很长,所以对于空开非常多的段是没有必要计算的。我们可以进行缩点,我选择的缩点范围是2520,它是10的阶乘,所以中间省去的部分无论怎么样都能跳到。看别人的题解,对于只有一种步长的进行了特判,个人认为没有必要,对b数组进行初始化以后,进行动态规划的时候会只规划这一种步长,只有满足从b[0]开始的才能规划成功。具体代码如下。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll  long long int
const int mod=1e9+7;
using namespace std;
int a[1010],b[1000100],c[10000010];
int main()
{
    /*ios::sync_with_stdio(false);*/
    ll n,k,i=0,j,m=0,sum=0,l;
    cin>>l>>n>>k>>m;
    memset(a,0,sizeof(a));
    memset(c,0,sizeof(c));
    for(i=1;i<=m;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+m+1);
    a[0]%=2520;
    a[1]%=2520;
    for(i=1;i<=m;i++)
    {
        b[i]=(a[i]-a[i-1])%2520;
    }
    for(i=1;i<=m;i++)
    {
        a[i]=a[i-1]+b[i];
        c[a[i]]=1;
    }
    memset(b,0x3f3f3f3f,sizeof(b));
    b[0]=0;
    a[m+1]=(l-a[m])%2520+a[m];
    for(i=1;i<=a[m+1]+k;i++)
    {
        for(j=n;j<=k;j++)
        {
            if(i>=j)
            {
                b[i]=min(b[i],b[i-j]+c[i]);
            }
        }
    }
    int ans=0x3f3f3f3f;
    for(i=a[m+1];i<=a[m+1]+k;i++)
        ans=min(ans,b[i]);
    cout<<ans;
  return 0;
}

3点石成金(题目链接

做动态规划做魔怔了,遇见这种有选择性的问题就想动态规划。这个题的数据非常小,所以可以直接枚举,具体见代码。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
using namespace std;
struct np
{
    long long int a,b,c,d;
 
}p[100];
struct  rp
{
    long long int m,q;
}e[100][2];
int main()
{
 long long int n,i=1,l,j,ans1=0,ans2=0,ans=0;
 cin>>n;
 for(i=0;i<100;i++)
    p[i].a=p[i].b=p[i].c=p[i].d=0;
for(i=1;i<=n;i++)
    cin>>p[i].a>>p[i].b>>p[i].c>>p[i].d;
    for(i=0;i<=1<<n+1;i++)
    {
        j=i;
        ans1=0;
        ans2=0;
        for(int k=0;k<20;k++)
        {
            if(j>>k&1)
            {
               ans1+=p[k].a;
               ans2-=p[k].b;
               if(ans2<0)
                        ans2=0;
            }
            else
            {
                ans1-=p[k].d;
                ans2+=p[k].c;
                if(ans1<0)
                    ans1=0;
            }
        }
        ans=max(ans,ans1*ans2);
    }
    cout<<ans;
    return 0;
}

4同余方程(题目链接

这个题是一个扩展欧几里得算法的板子题,主要为了加深一下前段时间欧几里得算法和费马小定理的印象。欧几里得算法和费马小定理
这个题最终求解的是一个正数,只需要把它加b即可。代码如下。

#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll long long int
const int mod=1e9+7;
using namespace std;
ll a,b,n,m;
void gcd(ll a,ll b,ll c,ll &n,ll &m)
{
    if(!b)
    {
        c=a;
        n=1;
        m=0;
    }
    else
    {
        gcd(b,a%b,c,m,n);
        m-=n*(a/b);
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    int i,j,k;
    cin>>a>>b;
    gcd(a,b,-1,n,m);
    while(n<0)
        n+=b;
    cout<<n;
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值