文章标题

来源:互联网 发布:淘宝床上用品床罩 编辑:程序博客网 时间:2024/06/09 16:53

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 longusing 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:
原创粉丝点击