CodeChef:Little Elephant and Colored Coins

类似墨墨的等式

设f[2][j][k]表示a[i].c是否和当前颜色相同,到当前枚举到的颜色为止,颜色数为j,对mnv取模为k的最小数 

这是个无限循环背包,用spfa优化

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map> 
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=30+10;
const int maxv=2*1e5+_;
LL inf;

LL f[2][maxn][maxv];//a[i].c是否和当前颜色相同,到当前枚举到的颜色为止,颜色数为j,对mnv取模为k的最小数 
struct SPFA
{
    int op,j,k;
    SPFA(){} SPFA(int OP,int J,int K){op=OP,j=J,k=K;}
}list[2*maxn*maxv];int head,tail;bool v[2][maxn][maxv];
void spfa(int cc,int mnv,int dv)
{
    head=1,tail=1; list[tail++]=SPFA(0,0,0);
    for(int j=1;j<=cc;j++)
        for(int k=0;k<mnv;k++)
        {
            if(f[0][j][k]!=inf)list[tail++]=SPFA(0,j,k),v[0][j][k]=true;
            if(f[1][j][k]!=inf)list[tail++]=SPFA(1,j,k),v[1][j][k]=true;
        }
    while(head!=tail)
    {
        int op=list[head].op,j=list[head].j,k=list[head].k;
        int tp=1,tj=j+1-op,tk=(k+dv)%mnv;
        if(f[tp][tj][tk]>f[op][j][k]+dv)
        {
            f[tp][tj][tk]=f[op][j][k]+dv;
            if(v[tp][tj][tk]==false)
            {
                v[tp][tj][tk]=true;
                list[tail]=SPFA(tp,tj,tk);
                tail++;if(tail==2*maxn*maxv)tail=1;
            }
        }
        v[op][j][k]=false;
        head++;if(head==2*maxn*maxv)head=1;
    }
}
    
struct node{int v,c;}a[maxn];
bool cmp(node n1,node n2){return n1.c<n2.c;}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,mnv=(1<<30);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i].v,&a[i].c),mnv=min(mnv,a[i].v);
    sort(a+1,a+n+1,cmp);
    
    int cc=1;
    memset(f,63,sizeof(f));inf=f[0][0][0];
    f[0][0][0]=0;
    for(int i=0;i<n;i++)//开始放第i+1种 
    {
        if(a[i+1].c!=a[i].c)
        {
            for(int j=1;j<=cc;j++)
                for(int k=0;k<mnv;k++)
                    f[0][j][k]=min(f[0][j][k],f[1][j][k]);
        }
        spfa(cc,mnv,a[i+1].v);
        if(a[i+1].c!=a[i].c)cc++;
    }
    for(int j=1;j<=cc;j++)
        for(int k=0;k<mnv;k++)
            f[0][j][k]=min(f[0][j][k],f[1][j][k]);
        
    int Q,u;LL x;
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%lld",&x);u=x%mnv;
        bool bk=false;
        for(int i=n;i>=1;i--)
            if(f[0][i][u]<=x){printf("%d\n",i);bk=true;break;}
        if(!bk)puts("-1");
    }
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKCqhzdy/p/10441319.html