2019 ICPC Malaysia National 部分题解

比赛链接
C.题意题,读懂之后枚举即可

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,s,cnt;
int main() {
	for(scanf("%d",&t);t;t--){
		printf("Case #%d: ",++cnt);
		scanf("%d%d",&n,&s);
		int ans=-2e9;
		for(int i=1;i<=n;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			if(y<=s)ans=max(ans,x);
			else ans=max(ans,x-(y-s));
		}
		cout<<ans<<'\n';
	}
 	return 0;
}

E.dp记录路径 ,注意:不能重复选和先出现的先选原则,所有倒着来dp即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,a[N],vis[1111][1111],pre[1111][1111];
int main() {
  ios::sync_with_stdio(false);
  while(1){
  	cin>>t;
  	if(!t)break;
  	memset(vis,0,sizeof vis);
  	memset(pre,0,sizeof pre);
  	cin>>n;vis[n+1][0]=1;
  	for(int i=1;i<=n;i++){
  		cin>>a[i];
  	}
  	for(int i=n;i>=1;i--){
  		for(int j=a[i];j<=t;j++){
  			if(vis[i+1][j-a[i]]){
  				vis[i][j]=1;
  				pre[i][j]=i;
  			}
  		}
  		for(int j=0;j<=t;j++){
  			if(!vis[i][j]){
  				vis[i][j]=vis[i+1][j];
  				pre[i][j]=pre[i+1][j];
  			}
  		}
  	}
  	for(int i=t;i>=0;i--){
  		if(vis[1][i]){
  			int la=i,l=1;
  			while(la){
  				cout<<a[pre[l][la]]<<' ';
  				int z=pre[l][la];
  				la-=a[pre[l][la]];
  				l=z+1;
  			}
  			cout<<i<<'\n';
  			break;
  		}
  	}
  }
 	return 0;
}

F.状态压缩dp,显然第一个排的每个人只能选 [ i e , i + e ] [i-e,i+e] 范围内的人,那么
d p [ i ] [ j ] dp[i][j] 表示第i个人 [ i e , i + e ] [i-e,i+e] 范围的人的状态(选了是1 不选为0)的选择方案数。
然后枚举所有人,枚举前一个人的所有状态,进行判断。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e3 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int dp[N][1<<10];
bool ban[N][N];
int n,e,k;
const int mod=1e9+7;
void add(int &x,int y){
	x+=y;
	if(x>=mod)x-=mod;
}
int main() {
  ios::sync_with_stdio(false);	
  cin>>n>>e>>k;
  for(int i=1;i<=k;i++){
  	int s,t;
  	cin>>s>>t;
  	ban[s][t]=1;
  }
  dp[0][0]=1;
  int c=2*e+1;
  for(int i=1;i<=n;i++){
  	int l=max(1,i-e);
  	int r=min(n,i+e);
  	int dx=max(1,i-1-e);
  	int dy=min(n,i-1+e);
  	for(int j=0;j<1<<c;j++){
  		for(int k=l;k<=dy;k++){
  			if(!((1<<(k-(i-1-e)))&j)){
  				if(!ban[i][k]){
  					add(dp[i][(j|(1<<k-(i-1-e)))>>1],dp[i-1][j]);
  				}
  			}
  		}
  		if(!ban[i][r]){
  			add(dp[i][j>>1|(1<<e+e)],dp[i-1][j]);	
  		}
  	}
  }
  cout<<dp[n][(1<<e+1)-1]<<endl;
 	return 0;
}

J.拓扑排序模板题。
ps:由于数据很小,所以其他的一些模拟做法都是可以的。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
vector<int>v[N];
int d[N],ans[10];
char a[5];
int main() {
  ios::sync_with_stdio(false);
  for(int i=1;i<=5;i++){
  	cin>>a+1;
  	if(a[2]=='>')v[a[3]-'A'].pb(a[1]-'A'),d[a[1]-'A']++;
  	else{
  		v[a[1]-'A'].pb(a[3]-'A');
  		d[a[3]-'A']++;
  	}
  }
  queue<int>q;
  for(int i=0;i<5;i++)if(!d[i])q.push(i);
  int cnt=0;
  while(!q.empty()){
  	int x=q.front();
  	q.pop();
  	ans[++cnt]=x;
  	for(auto k:v[x]){
  		if(--d[k]==0)q.push(k);
  	}
  }
  if(cnt!=5){
  	return cout<<"impossible\n",0;

  }
  for(int i=1;i<=5;i++){
  	cout<<(char)(ans[i]+'A');
  }
 	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/106173445