BZOJ 1386. [Baltic2000]Stickers 题解
BZOJ 1386. [Baltic2000]Stickers 题解
首先一个一个位置考虑,假设是\(z\)不够用了。
数位dp。
\(dp[i][j][0/1]\)表示\([0,10^i]\)内如果\(a_z=j\),前面的位是否存在非0数,的最小前缀(总共-用掉)
\(sum[i][j][0/1]\)表示考虑\([0,10^i]\)内如果\(a_z=j\)最后会剩下多少\(z\) 。
需要高精度。
code:
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
vector<int> operator + (vector<int> A,vector<int> B){
reverse(ALL(A));
reverse(ALL(B));
if(A.size()<B.size()) swap(A,B);
A.PB(0);
rep(i,A.size()){
if(i<B.size()) A[i]+=B[i];
if(A[i]>=10){
A[i+1]++;
A[i]-=10;
}
}
if(A.back()==0) A.POB();
reverse(ALL(A));
return A;
}
pair<vector<int>,vector<int> > operator + (pair<vector<int> ,vector<int> > A,pair<vector<int>,vector<int> > B){
return II(A.FIR+B.FIR,A.SEC+B.SEC);
}
vector<int> bigint(int num){
vector<int> ans;
while(num){
ans.PB(num%10);
num/=10;
}
reverse(ALL(ans));
return ans;
}
bool comp(vector<int> A,vector<int> B){
// A<B
if(A.size()!=B.size()) return A.size()<B.size();
return A<B;
}
bool comp(pair<vector<int>,vector<int> > A,pair<vector<int>,vector<int> > B){
return comp(A.FIR+B.SEC,B.FIR+A.SEC);
}
pair<vector<int>,vector<int> > dp[90+1][90+10+1][2];
pair<vector<int>,vector<int> > sum[90+1][90+10+1][2];
int a[10];
vector<int> Ans;
vector<int> Best;
int Z;
void solve(int D,int J,bool flag,pair<vector<int>,vector<int> > sma){
if(D==1){
pair<vector<int>,vector<int> > Nowsum;
rep(d,10){
if(d==0&&!flag);
else{
if(J<90){
Nowsum.SEC=Nowsum.SEC+bigint(90-J);
}
else{
Nowsum.FIR=Nowsum.FIR+bigint(J-90);
}
}
if(d==Z){
Nowsum.SEC=Nowsum.SEC+bigint(1);
}
if(comp(Nowsum,sma)){
Ans.PB(d);
break;
}
}
return ;
}
pair<vector<int>,vector<int> > Tmp;
rep(d,10){
if(comp(Tmp+dp[D-1][J-((flag||d)&&d==Z)][flag|(d!=0)],sma)){
Ans.PB(d);
solve(D-1,J-((flag||d)&&d==Z),flag|(d!=0),II(sma.FIR+Tmp.SEC,sma.SEC+Tmp.FIR));
return ;
}
Tmp=Tmp+sum[D-1][J-((flag||d)&&d==Z)][flag|(d!=0)];
}
}
void print(vector<int> V){
if(V.empty()){
puts("0");
return ;
}
for(auto it:V){
cout<<it;
}
cout<<endl;
}
int main(){
rep(i,10) scanf("%d",&a[i]);
int Pre=INF;
rb(Z_,1,10){
int z=Z_%10;
Z=z;
if(a[z]>=Pre) continue;
Pre=a[z];
rb(j,1,90+10) rep(flag,2) {
sum[1][j][flag].FIR.clear();
sum[1][j][flag].SEC.clear();
int f=10;
if(!flag){
f=9;
}
if(j>=90)
sum[1][j][flag].first=bigint(f*(j-90));
else
sum[1][j][flag].SEC=bigint(f*(90-j));
if(z!=0||flag){
sum[1][j][flag].SEC=sum[1][j][flag].SEC+bigint(1);
}
dp[1][j][flag].FIR.clear();
dp[1][j][flag].SEC.clear();
if(!comp(sum[1][j][flag].SEC,sum[1][j][flag].FIR)) dp[1][j][flag]=sum[1][j][flag];
}
rb(i,2,89){
rb(j,i,90+10){
rep(flag,2){
dp[i][j][flag].FIR.clear();
dp[i][j][flag].SEC.clear();
sum[i][j][flag].SEC.clear();
sum[i][j][flag].FIR.clear();
rep(d,10){
pair<vector<int>,vector<int> > Tmp=II(sum[i][j][flag].FIR+dp[i-1][j-((flag||d)&&d==z)][flag|(d!=0)].FIR,sum[i][j][flag].SEC+dp[i-1][j-((flag||d)&&d==z)][flag|(d!=0)].SEC);
if(!comp(dp[i][j][flag].FIR+Tmp.SEC,Tmp.FIR+dp[i][j][flag].SEC)){
dp[i][j][flag]=Tmp;
}
sum[i][j][flag]=sum[i][j][flag]+sum[i-1][j-((flag||d)&&d==z)][flag|(d!=0)];
}
}
}
}
Ans.clear();
solve(89,90+a[z],0,II(bigint(0),bigint(0)));
reverse(ALL(Ans));
while(Ans.size()&&Ans.back()==0) Ans.POB();
reverse(ALL(Ans));
if(z==1||comp(Ans,Best)){
Best=Ans;
}
}
reverse(ALL(Best));
Best[0]--;
rep(i,Best.size()){
if(Best[i]<0){
Best[i]+=10;
Best[i+1]--;
}
}
if(Best.back()==0){
Best.POB();
}
reverse(ALL(Best));
for(auto it:Best){
printf("%d",it);
}
return 0;
}