gym100222 A,C,E 题解

89 篇文章 1 订阅

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,wid)+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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值