luogu P2737

题目链接

题意,给一些数,问最大的不能被这些数表示出来的数(自由相加)是多少。(大凯的疑惑)

解法

一个想法是dp,然后对答案有影响的上界接近于最大数的平方。
这个和noip 2018 d1t2也差不多

另一个做法是先选择这些数中的一个数,我们为了方便就选最小的一个mn,然后可以发现如果可以表示出x,那么 x + m n , x + 2 × m n , x + 3 × m n x+mn,x+2\times mn,x+3\times mn 等都是可以被表示出来的,所以我们将其它的数按对mn取模的值分类。这样就可以对[0,mn-1]这里面的每个数 i i 计算最小的可以被原数列表示出来的数,同时对 m n mn 取模等于 i i .然后再这些最小值里取一个最大的,就是答案了。
然后怎么求这些最小值呢,这里可以使用最短路的方法,将每个数看成一条边进行转移(这里和dp有点像)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,m,a[maxn],mn,alfa[maxn],cnt,mp[maxn];
typedef pair<int,int> pii;
vector<pii> e[maxn];
inline void add(int a,int b,int c){
	e[a].push_back(pii(b,c));
}
priority_queue<pii,vector<pii>,greater<pii> > q;
int dis[maxn],vis[maxn];
const int inf=0x3f3f3f3f;
void dj(){
	for(int i=1;i<mn;i++){dis[i]=-1;}
	q.push(pii(0,0));
	while(!q.empty()){
		int u=q.top().second;q.pop();
		if(vis[u])continue;
	//	while(vis[u]){u=q.top().second;q.pop();}
		vis[u]=1;
		pii v;int l=e[u].size();
		for(int i=0;i<l;i++){
			v=e[u][i];//printf("%d %d\n",u,v.first);
			if((dis[v.first]==-1)||(dis[v.first]>dis[u]+v.second)){
				dis[v.first]=dis[u]+v.second;
				q.push(pii(dis[v.first],v.first));
			}
		}
	}
}
int main(){
	//freopen("8.in","r",stdin);
	//freopen("8.out","w",stdout);
	n=read();//m=read();
	mn=0x3f3f3f3f;
	for(int i=1;i<=n;i++){
		a[i]=read();
	//	for(int j=a[i];j>=max(1,a[i]-m);j--){mp[j]=1;}
	}
/*	for(int i=1;i<=3000;i++){
		if(mp[i]){alfa[++cnt]=i;}
	}
	n=cnt;mn=3001;
	for(int i=1;i<=n;i++){
		a[i]=alfa[i];
		//printf("%d\n",a[i]);
	}*/
	for(int i=1;i<=n;i++){
		if(mn>a[i])mn=a[i];
	}
//	printf("%d\n",mn);
	for(int i=0;i<mn;i++){
		for(int j=1;j<=n;j++){
	//		printf("%d %d\n",i,(i+a[j])%mn);
			add(i,(i+a[j])%mn,a[j]);
		}
	}
	dj();
	int mx=0,flag=1;
	for(int i=0;i<mn;i++){
		if((dis[i]==-1)||(dis[i]-mn>inf)){flag=0;break;}
	//	printf("%d %d\n",i,dis[i]);
		mx=max(mx,dis[i]);
	}
	if(!flag){puts("0");}
	else{
		printf("%d\n",max(mx-mn,0));
	}
	return 0;
}

(这里有些注释的代码是因为这本来是另一道题,但是双倍经验了)
这个的复杂度 O ( n m i n ( a [ i ] ) + n l o g ( n ) ) O(n*min(a[i])+nlog(n)) ,比dp快很多

发布了62 篇原创文章 · 获赞 1 · 访问量 1010

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103723442