gym100222 A,C,E 题解
A
背包问题!
首先可以发现一件事情:戒掉的那 k k k个一定是着迷度最小的 k k k个。
然后接着可以发现,从小往大戒不会使答案变得更差。
所以定义 d p i dp_{i} dpi表示戒掉前i个要多少天, v a l i val_i vali表示戒掉的东西着迷度至少为 i i i的最少天数,则 d p i = v a l max ( 0 , w i − d ) + 1 dp_i=val_{\max(0,w_i-d)}+1 dpi=valmax(0,wi−d)+1,接着把 w i w_i wi当重量, d p i dp_i dpi当价值放入 v a l val val背包。
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#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;
typedef pair<int,int> mp;
/*}
*/
const int MAXA=10000+20;
const int MAXN=5000+20;
LL rest=0;
vector<string> v;
LL need[MAXA];
int n,d;
typedef pair<int,string> HOB;
HOB hobbies[MAXN];
int main(){
freopen("addict.in","r",stdin);
freopen("addict.out","w",stdout);
fastio;
memset(need,127,sizeof(need));
LL INF=need[0];
need[0]=0ll;
cin>>n>>d;
rb(i,1,n){
cin>>hobbies[i].SEC>>hobbies[i].FIR;
}
sort(hobbies+1,hobbies+1+n);
rb(i,1,n){
LL Extra=need[max(0,hobbies[i].FIR-d)];
if(Extra==INF) break;
LL dp=Extra+1;
rl(j,10000,hobbies[i].FIR)
if(need[j-hobbies[i].FIR]!=INF)
check_min(need[j],need[j-hobbies[i].FIR]+dp);
rl(j,9999,0)
check_min(need[j],need[j+1]);
rest+=dp;
v.PB(hobbies[i].SEC);
}
sort(ALL(v));
cout<<v.size()<<' '<<rest<<'\n';
for(auto it:v){
cout<<it<<'\n';
}
return 0;
}/*
*/
C
正常的 d p dp dp相信大家都能想到 d p i , j dp_{i,j} dpi,j表示放了前j个结尾这k个和字符串i一样。
但是这样×起来会远超double 甚至 long double 的精度。不过这里对概率只有乘的操作,我们就可以把概率改成 log 2 \log_2 log2来计算。
由于0.00000000000000…1的差别都会被log放大,而且log的值也不会特别大。
注意是可以从相同的字符转移到相同字符的,不然会wa8
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#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;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXT=27;
const int MAXN=1001;
const int MAXD=4001;
vector<pair<int,int> > g[MAXD];
int n,d,k,t;
long double p[MAXN][MAXT];
string s[MAXD];
pair<long double,int> dp[MAXD][MAXN];//record last string
map<string,bool> app;
void print(int i,int j){
if(j==k){
cout<<s[i];
return ;
}
print(dp[i][j].SEC,j-1);
cout<<s[i][k-1];
}
int main(){
fastio;
freopen("decoding.in","r",stdin);
freopen("decoding.out","w",stdout);
cin>>d>>k>>t;
rb(i,1,d){
cin>>s[i];
}
rb(i,1,d)
rb(j,1,n)
dp[i][j]=II(0.0,0);
rb(i,1,d){
if(app[s[i]]){
d--;
rb(j,i,d){
s[j]=s[j+1];
}
}
else
app[s[i]]=true;
}
cin>>n;
rb(i,1,n)
rep(j,t)
cin>>p[i][j];
rb(i,1,d)
rb(j,1,d){
//check can j go to i?
bool ok=true;
rb(l,1,k-1){
ok = ok &(s[j][l]==s[i][l-1]);
}
if(ok){
g[i].PB(II(j,s[i][k-1]-'a'));
}
}
rb(i,1,d){
dp[i][k]=II(0.0,0);
rb(j,1,k){
dp[i][k].FIR+=log(p[j][s[i][j-1]-'a']);
}
}
rb(i,k+1,n){
rb(j,1,d){
pair<long double,int> last=II(-999999999999999.0,-1);
for(auto it:g[j]){
long double z=dp[it.FIR][i-1].FIR+log(p[i][it.SEC]);
int las=it.FIR;
if(z>last.FIR)
last=II(z,las);
}
dp[j][i]=last;
}
}
pair<long double,int> rest=II(-999999999999.0,-1);
rb(i,1,d){
if(dp[i][n].FIR>rest.FIR)
check_max(rest,II(dp[i][n].FIR,i));
}
if(rest.FIR<=-999999999999.0) cout<<"---\n";
else{
print(rest.SEC,n);
}
return 0;
}
/** 程序框架:
**/
E
思路大概就是把0点拆成两个点,然后就是一个正常的环了,通过线段树上二分,可以做到 O ( n × log n ) O(n\times \log n) O(n×logn)
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#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;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int N=1<<20;
struct SGT{
int tree[N+N];
void mark(int index){
index+=N-1;
tree[index]=0;
index>>=1;
while(index){tree[index]=tree[index<<1]+tree[index<<1|1],index>>=1;}
}
int search(int val,int now=1,int l=1,int r=N+1){
if(l==r-1) return l;
if(tree[now<<1]>=val) return search(val,now<<1,l,(l+r)>>1);
return search(val-tree[now<<1],now<<1|1,(l+r)>>1,r);
}
int query(int a,int b,int now=1,int l=1,int r=N+1){
if(r<=a||l>=b){
return 0;
}
if(r<=b&&l>=a){
return tree[now];
}
int mid=(l+r)>>1;
return query(a,b,now<<1,l,mid)+query(a,b,now<<1|1,mid,r);
}
}sgt;
int nn;
int nex[N],pre[N];
bool deled[N];
int n,m,k;
void del(int pos){
if(deled[pos]) return;
// cout<<pos<<endl;
deled[pos]=true;
sgt.mark(pos);
nex[pre[pos]]=nex[pos];
pre[nex[pos]]=pre[pos];
if(pos==1) del(m+2);
if(pos==m+2) del(1);
}
int main(){
freopen("infinity.in","r",stdin);
freopen("infinity.out","w",stdout);
cin>>m>>n>>k;
--k;
int now=1;
nn=n+m+2;
nex[nn]=1;
pre[1]=nn;
rb(i,1,nn-1){
nex[i]=i+1;
pre[i+1]=i;
}
rl(i,N+N-1,1) sgt.tree[i]=(i<N? sgt.tree[i<<1]+sgt.tree[i<<1|1]:bool(i-N<nn));
rb(i,1,n+m){
int go=(k)%(sgt.tree[1]);
// cout<<"!"<<now<<' '<<go<<' '<<sgt.tree[1]<<endl;
// cout<<go<<' '<<sgt.tree[1]<<endl;
if(go==0){
del(now);
now=nex[now];
continue;
}
int bef=sgt.query(1,now+1);
int aft=sgt.tree[1]-bef;
// cout<<bef<<' '<<aft<<endl;
if(aft>=go){
int NEX=sgt.search(bef+go);
// cout<<NEX<<' '<<m<<' '<<nex[NEX]<<endl;
del(NEX);
now=NEX;
}
else{
go=go-aft;
int NEX=sgt.search(go);
del(NEX);
now=NEX;
}
while(deled[now]) now=nex[now];
}
int remain=sgt.search(1);
if(remain==1||remain==m+2){
cout<<0<<endl;
}
else
if(remain<=m+1){
cout<<remain-1<<endl;
}
else{
cout<<-(remain-(m+2))<<endl;
}
return 0;
}