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; }
pain and happy in the cruel world.