文章标题

Spot
描述
有n个泥点,排成一排,第i个泥点坐标为ai。有m个木板,第i个木板长为li。现在用尽可能少的木板覆盖所有泥点。
问:使用木板的最少数量以及最优方案数(mod 1000000007),若不能完全覆盖,请输出“NO”。
注意:
泥点可重复覆盖,木板可重叠。
计算方案时,长度相等的两个板不等价,视为两种板。
输入
第1行:一个数n
第2行:n个数a1,a2…an(从小到大给出)
第3行:一个数m
第4行:m个数l1,l2…ln
输出
第1行,一个数,使用木板的最少数量
第2行,一个数,最优方案数
若不能完全覆盖,请输出“NO”
样例输入
1
0
1
10
样例输出
1
10
数据范围和约定
对于20%的数据:n=1
对于另外20%的数据:m=1
对于100%的数据:
1<=n,m<=15
0<=ai<=1000000000
1<=li<=1000000000
时空限定
内存限制为 512 MB
时间限制为 1 s
评测环境和细则
评测开启-O2优化
评测软件为lemon
评测忽略行尾空格
文件名
提交文件名为spot.cpp/pas
输入文件名为spot.in
输出文件名为spot.out

n,m<=15,先确定是状压

一开始f[i][j],i表示前i个木板,j压的是泥点
再用g[i][j] 在dp的时候记录方案数
但是要考虑的情况会多到爆炸
在卡了一个下午后,本蒟蒻毅然决然的决定 换!状!态!!!!

用f[i][j],i表示前i个泥点,j压的是木板,f[i][j]表示方案数
初始化成负数
最后再扫一遍f[n][0-maxp],找不是负数中最小的,没找着就输出”NO”
这样比以前的好处是:
泥点最后一定要全都选完,但木板不一定,比较好转移。

错误的第一次code

#include<cstdio>
#include<cstring>
#include<iostream>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int mod=1000000007;
const int N=1<<15;
ll minn(ll a,ll b){return a<b?a:b;}
ll maxn(ll a,ll b){return a>b?a:b;}

int n,m,maxp;
int pos[21],len[21];
int f[16][N+10];
ll g[16][N+10];
ll num;
ll ans;

void out11()
{
    printf("\n\n");
    for(int i=1;i<=m;++i)
    {
        for(int j=0;j<=maxp;++j)
          printf("%d ",f[i][j]);
        printf("\n");
    }
    printf("\n");
    for(int i=0;i<=m;++i)
    {
        for(int j=0;j<=maxp;++j)
          printf("%lld ",g[i][j]);
        printf("\n");
    }
    printf("\n");
}

int main(){
    //freopen("1.txt","r",stdin);
    freopen("spot6.in","r",stdin);
    //freopen("spot5.in","r",stdin);
    //freopen("spot.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
      scanf("%d",&pos[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
      scanf("%d",&len[i]);

    // n为泥点个数  m为木板个数
    maxp=(1<<n)-1;
    mem(f,0x7f);
    f[0][0]=0;
    g[0][0]=1;
    int r,temp,l1,r1,l2,r2,judge1;
    ll llnum,lrnum,rrnum,rlnum,fangan;
    ll temp1,temp2;
    int qian,now;
    for(int i=1;i<=m;++i)
      for(int j=0;j<=maxp;++j)
      {
            if(f[i][j]==f[i-1][j]){g[i][j]=(g[i-1][j]+g[i][j])%mod;}
            else if(f[i][j]>f[i-1][j]){f[i][j]=f[i-1][j];g[i][j]=g[i-1][j];}
            qian=maxp+1;
            for(int l=1;l<=n;++l)
            {
                r=l;temp=j;
                while(pos[r]-pos[l]+1<=len[i]&&r<=n)++r;--r;

                now=0;
                for(int p=l;p<=r;++p)
                  if(temp&(1<<(p-1)))
                    now|=(1<<(p-1));
                if(now==qian)continue;
                qian=now;

                judge1=0;
                for(int p=l;p<=r;++p)
                {
                    l2=p;
                  if(temp&(1<<(p-1)))
                  {
                        judge1=1;
                      break;
                    }
                }
                for(int p=r;p>=l;--p)
                {
                    r2=p;
                  if(temp&(1<<(p-1)))
                    break;
                }
                if(!judge1)continue;//选的区间中 状态都没有 

                l1=l2-1;
                while(l1>=1&& !((1<<(l1-1))&temp) )--l1;
                r1=r2+1;
                while(r1<=n&& !((1<<(r1-1))&temp) )++r1;
                llnum=(l1==0?-0x7fffffff:pos[l1]+1);
                lrnum=pos[r2]-len[i]+1;
                rlnum=pos[l2]+len[i]-1;
                rrnum=(r1==n+1?0x7fffffff:pos[r1]-1);
                temp1=minn(rlnum,rrnum)-pos[r2]+1;
                temp2=pos[l2]-maxn(llnum,lrnum)+1;
                //printf("temp1=%lld temp2=%lld\n",temp1,temp2);
                fangan=(minn(temp1,temp2))%mod;
                //if(fangan<0)
                //  cout<<fangan<<endl;
                //printf("i=%d j=%d l=%d r=%d lnum=%lld rmun=%lld fangan=%lld\n",i,j,l,r,lnum,rnum,fangan);

                for(int p=l;p<=r;++p)
                  temp=temp&(~(1<<(p-1)));
                if(f[i][j]==f[i-1][temp]+1)
                    g[i][j]=(g[i][j]+g[i-1][temp]*fangan%mod)%mod;
                else
                    if(f[i][j]>f[i-1][temp]+1)
                    {
                        f[i][j]=f[i-1][temp]+1;
                        g[i][j]=g[i-1][temp]*fangan%mod;
                    }
            }
        }

    if(f[m][maxp]==f[0][maxp])
    {
        printf("NO");
        //while(1);
        return 0;
    }
    printf("%d\n",f[m][maxp]);
    for(int i=1;i<=m;++i)
      if(f[i][maxp]==f[m][maxp])
        ans=(ans+g[i][maxp])%mod;
    printf("%lld",ans);
    //可以用dfs??? 
    //dfs(int x,int now)
    //外面一个judge数组或二进制变量记录泥点选没选
    //x:第几块木板
    //now:以前用的木板数 
    //可能左右挪比较恶心吧!!!

    /*judge=0;
    dfs(1,0,1);*/
    //out11();
    while(1);
    return 0;
}

正确的大神第一次想的那样的标程:



AC我的code:






























评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值