题解:P13068 [GCJ 2020 #3] Pen Testing
思考一下这个操作,发现只有把一支笔写到没有墨才能获得一些能够帮助我们决策的信息。并且我们也不会一直选没有被写过的笔,因为这样和随机选没有本质区别。
这样一个朴素的想法就是我们可以写干一些墨水比较少的笔,来提高接下来取到剩余墨水高的笔的概率。事实上,这里我们让所有笔都书写
接下来我们进行搜索,来找出每一个状态对应的最优决策。
设数组
-
直接选择两支笔带走。那么在随机的情况下我们显然会决策两支当前试写次数最少的笔。
-
继续试写。延续上文朴素的想法,这里我们既希望能够把墨水较少的笔写干,又希望能够留下一些试写次数尽量少的笔。那么我们可以选择试写次数不超过当前已写干墨水的笔的墨水最大值中试写次数最多的那一个,尝试用这支笔去更新
vis 集合。同时这个时候我们写干的笔一定是一个从0 开始的前缀。
形式化地,假设当前
其中
带入
// Written by Mi2uk1
// Try Harder.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define i28 __int128
#define ull unsigned long long
#define pii pair<int,int>
#define pll pair<long long,long long>
#define fir first
#define INF (1e9)
#define sec second
#define pb push_back
#define eb emplace_back
const int N=30+9,M=(1<<12)+9;
const int MOD=998244353;
const double eps=1e-9;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline void chkmax(ll &x,ll y){x=x<y?y:x;}
inline void chkmin(ll &x,ll y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
int ret=1;
while(b){
if(b&1) ret=1ll*ret*a%p;
a=1ll*a*a%p;
b>>=1;
}
return ret;
}
#define fir first
#define sec second
double tsum=0;
map<pair<vector<int>,int>,double> mp1;
map<pair<vector<int>,int>,bool> mp2;
double dfs(vector<int> a,int k,int N=15){
if(a.size()<2) return 0;
sort(a.begin(),a.end());
if(mp1.count({a,k})) return mp1[{a,k}];
double cst=0,cwr=0;
for(int i=k;i<N;++i){
for(int j=i+1;j<N;++j){
if(i<a[0] || j<a[1]) continue;
if(i+j>=N+a[0]+a[1]){
double coef=0,cnt=1;
if(i>=a[0] && j>=a[1]) coef+=1;
if(i>=a[1] && j>=a[0]) coef+=1;
for(int pos=a.size()-1;pos>=2;--pos){
int us=N-max(k,a[pos]);
if(i>=a[pos]) --us;
if(j>=a[pos]) --us;
if(us<=a.size()-1-pos){cnt=0; break;}
cnt=cnt*(us-(a.size()-1-pos));
} cst+=coef*cnt;
}
}
}
int tpos=-1;
for(int i=a.size()-1;i>=0;--i)
if(a[i]<=k){tpos=i; break;}
if(tpos==-1){
mp2[{a,k}]=1;
return mp1[{a,k}]=cst;
}
vector<int> tmp;
//success
tmp=a; tmp[tpos]++;
cwr+=dfs(tmp,k);
//failed
if(a[tpos]==k){
tmp=a; tmp.erase(tmp.begin()+tpos);
cwr+=dfs(tmp,k+1);
}
mp2[{a,k}]=(cst>=cwr); ++tsum;
return mp1[{a,k}]=max(cst,cwr);
}
bool ed[100009];
vector<pair<int,int> > a[100009];
vector<int> ask;
int ans[100009][2];
int k[100009],ta[100009],tpos[100009];
mt19937 rd(random_device{}());
int id[19];
void Mian(){
int T,N,C; cin>>T>>N>>C;
vector<int> st(N,0);
dfs(st,0);
for(int j=1;j<=T;++j){
for(int i=1;i<=N;++i) a[j].push_back({i,0});
k[j]=0; ed[j]=0;
}
while(1){
bool flg=0; ask.clear();
for(int j=1;j<=T;++j){
ta[j]=0;
if(ed[j]){ask.pb(0); continue;}
vector<int> tmp;
for(int i=0;i<a[j].size();++i)
tmp.push_back(a[j][i].sec);
sort(tmp.begin(),tmp.end());
if(mp2[{tmp,k[j]}]){
sort(a[j].begin(),a[j].end(),[](pair<int,int> a,pair<int,int> b){
return a.sec<b.sec;
});
ans[j][0]=a[j][0].fir; ans[j][1]=a[j][1].fir;
ed[j]=1; ask.pb(0);
}else{
int tmx=-1; tpos[j]=-1;
for(int i=0;i<a[j].size();++i)
if(a[j][i].sec<=k[j] && a[j][i].sec>tmx) tpos[j]=i,tmx=a[j][i].sec;
if(tpos[j]==-1){
sort(a[j].begin(),a[j].end(),[](pair<int,int> a,pair<int,int> b){
return a.sec<b.sec;
});
ans[j][0]=a[j][0].fir; ans[j][1]=a[j][1].fir;
ed[j]=1; ask.pb(0);
}else{
ask.pb(a[j][tpos[j]].fir); ta[j]=1; flg=1;
}
}
}
for(int i=0;i<T;++i) cout<<ask[i]<<' '; cout<<endl;
if(!flg){
for(int i=1;i<=T;++i)
cout<<ans[i][0]<<' '<<ans[i][1]<<' '; cout<<endl;
return ;
}
for(int j=1;j<=T;++j){
int res; cin>>res;
if(!ta[j] || ed[j]) continue;
if(res) a[j][tpos[j]].sec++;
else{
a[j].erase(a[j].begin()+tpos[j]);
++k[j];
}
}
}
}
void Mianclr(){
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
//freopen("ftc1.in","r",stdin);
//freopen("r.out","w",stdout);
int c,T=1; //cin>>T;
while(T--){
Mianclr();
Mian();
}
}