CF #536 (Div. 2) A(暴力判断)B(模拟)C(规律)D(规律,BFS)E(思维,扫描线,DP,)

Contest:http://codeforces.com/contest/1106

也是隔了好久的题了,最近整理一波。差了一道,看情况写写吧。

A. Lunar New Year and Cross Counting(暴力判断)

题目链接:http://codeforces.com/contest/1106/problem/A

题目大意:找一个图中有多少个

X.X
.X.
X.X

形状的局部图。

思路:图的大小是500*500,直接暴力就好了。

ACCode:

const int MAXN=5e2+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0); 

char mp[MAXN][MAXN];

int main(){
	int n;
	while(cin>>n){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				cin>>mp[i][j];
			}
		}
		int ans=0;
		for(int i=2;i<n;++i){
			for(int j=2;j<n;++j){
				if(mp[i][j]=='X'){
					if(mp[i-1][j+1]==mp[i][j]&&mp[i-1][j-1]==mp[i][j]
					&& mp[i+1][j+1]==mp[i][j]&&mp[i+1][j-1]==mp[i][j]){
						ans++;
					}
				}
			}
		}
		cout<<ans<<endl; 
	}
}

B. Lunar New Year and Food Ordering(模拟)

题目链接:http://codeforces.com/contest/1106/problem/B

题目大意:一个餐馆有n种菜品,有m个顾客依次就餐,然后。输入n个菜品的数量和单价。之后m行,每行输入一个顾客的点菜和点菜数量。

顾客只有在吃完所有的菜之后才会付钱,否则就不会付钱。如果顾客要求的菜品不够,那么将从最便宜的菜品中选。(顾客吃菜之后,菜的数量会减少),问每个顾客的花费。

思路:首先按价格排序,然后模拟即可。加一个标记k,表示k菜品之前的所有菜品都没有了。

ACCode:

const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0); 

struct node{
	int id;
	ll num,cost;
}arr[MAXN];
ll num[MAXN],cost[MAXN];

int cmp(node a,node b){
	if(a.cost==b.cost)
		return a.num<b.num;
	return a.cost<b.cost;
}
int main(){
	int n,m;
	while(cin>>n>>m){
		for(int i=1;i<=n;++i){
			cin>>num[i];
		}
		for(int i=1;i<=n;++i){
			cin>>cost[i];
		}
		for(int i=1;i<=n;++i){
			arr[i]={i,num[i],cost[i]};
		}sort(arr+1,arr+1+n,cmp);
		ll need,kind,speed,k=1;
		while(m--){
			cin>>kind>>need;
			speed=0;
			if(num[kind]>=need){
				num[kind]-=need;
				speed=need*cost[kind];
				cout<<speed<<endl;
				continue;
			}
			else if(num[kind]>0){
				need-=num[kind];
				speed+=num[kind]*cost[kind];
				num[kind]=0;
			}
			for(int i=k;i<=n;++i){
				k=i;
				if(num[arr[i].id]==0)	continue;
				if(num[arr[i].id]>=need){
					num[arr[i].id]-=need;
					speed+=need*cost[arr[i].id];
					need=0;break;
				}
				else{
					need-=num[arr[i].id];
					speed+=num[arr[i].id]*cost[arr[i].id];
					num[arr[i].id]=0;
				}
			}
			if(need>0)	speed=0;
			cout<<speed<<endl;
		}
	}
}

C. Lunar New Year and Number Division(规律)

题目链接:http://codeforces.com/contest/1106/problem/C

题目大意:给你n个数,让你从中两两选择组成一些数,满足\sum_{i=j}^{m}s_j^2最小。输出这个数。

思路:很明显的规律,拍一下序,然后最前面的和最后面的两两组合。(题目保证输入数据为偶数个)。

ACCode:

const int MAXN=3e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0); 

ll arr[MAXN];

int main(){
	int n;
	while(cin>>n){
		for(int i=1;i<=n;++i){
			cin>>arr[i];
		}
		sort(arr+1,arr+1+n);
		ll ans=0;
		for(int i=1;i<=n/2;++i)
			ans+=(arr[i]+arr[n-i+1])*(arr[i]+arr[n-i+1]);
		cout<<ans<<endl;
	}
}

D. Lunar New Year and a Wander(规律,BFS)

题目链接:http://codeforces.com/contest/1106/problem/D

题目大意:给出一个图,从节点1开始。找出遍历这个图的字典序最小的路线(重复的走的节点只记录第一次经过的位置)。

思路:建好图之后直接搜索就好了。因为重复经过的节点记录一次就不记录了。因此BFS,每次找字典序最小的那个点就好了

ACCode:

const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);

struct cmp{
	bool operator()(const int &a,const int &b){
		return a>b;
	}
};
vector<int> vec[MAXN];
priority_queue<int,vector<int>,cmp> que;
int vis[MAXN];
int n,m;
void bfs(){
	clean(vis,0);
	while(que.size())	que.pop();
	que.push(1);
	vis[1]=1;
	while(que.size()){
		int e=que.top();que.pop();
		cout<<e<<" ";
		int len=vec[e].size();
		for(int i=0;i<len;++i){
			if(vis[vec[e][i]]==0){
				que.push(vec[e][i]);
				vis[vec[e][i]]=1;
			}
		}
	}cout<<endl;
}
int main(){
	while(cin>>n>>m){
		for(int i=1;i<MAXN;++i){
			vec[i].clear();
		}
		int a,b;
		for(int i=1;i<=m;++i){
			cin>>a>>b;
			vec[a].push_back(b);
			vec[b].push_back(a);
		}
		bfs();
	}
}

E. Lunar New Year and Red Envelopes(思维,扫描线,DP,)

题目链接:http://codeforces.com/contest/1106/problem/E

题目大意:有长度为n的时间段,m次打扰,k个红包。每个红包有到达时间,消失时间,收集僵直时间(收集完这个红包之后di时间内不能收集红包了),和价值。在一个时间点上,如果有多个红包,一定会取最大的那个金额的红包。每次干扰的时候(设干扰时间点为x),Bob就在这个时间点无法收取红包,但在x+1时刻就可以收取红包了。我们想用少于m此机会使得Bob收集的红包金额最小,问最小是多少?

思路:一看题,就知道是一个很明显的动态规划问题。

首先得出Bob所能获得的红包的最大价值。可以用扫描线来获得。扫描时间点,每个时间点都进行比较。

然后,对于每个时间点,我们可以选择干扰||不干扰,转换成动态规划问题。

状态转移方程:对于j次打扰。

f[j+1][i+1]=min(f[j+1][i+1],f[j][i]);

f[j][a[i].d+1]=min(f[j][a[i].d+1],f[j][i]+a[i].w);

因为n*m比较大,因此用滚动数组来优化。

ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include<stdio.h>
#include<string.h>
#include<math.h>

#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;

#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ˮӡ
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const double EPS=1.0e-8;
const double PI=acos(-1.0);

struct node{
	int d,w,t;
	bool operator <(const node &e)const {
		return w>e.w||(w==e.w&&d>e.d);
	}
};
vector<node> e[MAXN];
node a[MAXN];
map<node,int> cur;
ll f[2][MAXN],ans=INF64;
int n,m,k;

void Insert(node x){
	if(cur.count(x)) cur[x]++;
	else cur[x]=1;
}
void Erase(node x){
	cur[x]--;
	if(cur[x]==0) cur.erase(x);
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	int s,t,d,w;
	for(int i=1;i<=k;++i){
		scanf("%d%d%d%d",&s,&t,&d,&w);
		e[s].push_back(node{d,w,1});
		e[t+1].push_back(node{d,w,-1});
	}
	for(int i=1;i<=n;++i){
		for(int it=0;it<e[i].size();++it){
			if(e[i][it].t==1) Insert(e[i][it]);
			else Erase(e[i][it]);
		}
		if(cur.size()) a[i]=(*(cur.begin())).first;//这个时间点有红包
		else a[i]=node({i,0,0});//没有红包
	}clean(f,0x3f);
	f[0][1]=0;
	for(int j=0;j<=m;++j){
		clean(f[(j^1)&1],0x3f);
		for(int i=1;i<=n;++i){
			f[(j^1)&1][i+1]=min(f[(j^1)&1][i+1],f[j&1][i]);
			f[j&1][a[i].d+1]=min(f[j&1][a[i].d+1],f[j&1][i]+a[i].w);
		}ans=min(ans,f[j&1][n+1]);
	}printf("%lld\n",ans);
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值