NJUST 第一次集体个人赛

题目网址: http://njoj.org/Contest/80/

B题

水题,题目标程有错...注意边界条件。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define Maxn 100005
using namespace std;

int a[Maxn];
int main(){
	int n,m;
	while (~scanf("%d%d",&n,&m)){
		for (int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		sort(a+1,a+1+n);
		int ans=0;
		for (int i=1;i<=n-1;i++){
			if (a[i+1]-a[i]>=200){
				ans+=(a[i+1]-a[i]-200)*2;
			}
		}
		if ((2000-a[n])*2>200){
			ans+=(2000-a[n])*2-200;
		}
		if (a[1]>200) ans+=a[1]-200;
		ans+=a[1];
		if (ans>m) printf("HeHe~\n");
		else printf("HaHa~\n");
	}
	return 0; 
}

D题

题目大意:给出一个1到n的排列,求有多少子序列 的中位数恰好是b。

分析:显然,左边比b大的数-左边比b小的数=右边比b小的数-右边比b大的数。

那,我们在左边找出  比b大的数-比b小的数=i 的总数有多少个。在同样求解右边的时候,便可以找到相应的答案累加。

#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 201000
#define Maxn 100005
using namespace std;

int a[MAXN];
int r[MAXN];
int main(){
	int cases,n,m,p,k;
	scanf("%d",&cases);
	while (cases--){
		scanf("%d%d",&n,&m);
		memset(r,0,sizeof(r));
		for (int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			if (a[i]==m) p=i;
		}
		k=Maxn;
		r[Maxn]=1;
		for (int i=p+1;i<=n;i++){
			if (a[i]>m) k++;
			else k--;
			r[k]=r[k]+1;
		}
		k=Maxn;
		int ans=r[Maxn];
		for (int i=p-1;i>=1;i--){
			if (a[i]>m) k++;
			else k--;
			ans=ans+r[Maxn+Maxn-k];
		}
		printf("%d\n",ans);
	}
	return 0;
}

E题

求解阶梯型的小巷 最多容下多少水。

分析:最多只有一个”小山峰“能露出山头。我们找到最高的山峰(阶梯)之后,设为 Maxk,从1到Maxk做一次,n到Maxk做一次。

我写的有点复杂,思路还是很简单的。

#include <iostream>
#include <cstring>
#include <cstdio>
#define Maxn 100010
#define LL long long
using namespace std;

int a[Maxn],len[Maxn];
int main(){
	int n;
	LL wide,length;
	while (~scanf("%d%lld",&n,&wide)){
		int Maxk=0;a[0]=0;
		for (int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
			if (a[i]>a[Maxk]) Maxk=i;
		}
		for (int i=1;i<=n;i++){
			scanf("%lld",&len[i]);
		}
		LL ans=0;
		int p=1;
		while (a[p]<=a[p+1]) p++;
		while (p<Maxk){
			int q=p+1;
			while (q<=Maxk&&a[q]<a[p]) q++;
			if (q<=Maxk){
				LL tmp=min(a[q],a[p]);
				for (int j=p+1;j<=q-1;j++){
					ans+=(tmp-a[j])*len[j];
				}
			}
			else break;
			p=q;
			while (p<Maxk&&a[p]<=a[p+1]) p++;
		}
		p=n;
		while (a[p]<=a[p-1]) p--;
		while (p>Maxk){
			int q=p-1;
			while (q>=Maxk&&a[q]<a[p]) q--;
			if (q>=Maxk){
				LL tmp=min(a[q],a[p]);
				for (int j=p-1;j>=q+1;j--){
					ans+=(tmp-a[j])*len[j];
				}
			}
			else break;
			p=q;
			while (p>Maxk&&a[p]<=a[p-1]) p--;
		}
		printf("%lld\n",ans*wide);
	}
	return 0;
}

F题

按照题目要求,我们可以划分为0到k个阶段,第i个阶段最多打 i 枪。

我们可以从后往前做,push第 i 阶段的所有元素进去,再pop 最大元素出来 即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define LL long long
#define Maxn 200050
using namespace std;

priority_queue<LL> big;
LL a[Maxn];
int main(){
	int n,c,k;
	while (~scanf("%d%d",&n,&c)){
		for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
		if (c==0) c=1;
		k=n/c;
		LL ans=0;
		while (!big.empty()) big.pop();
		
		for (int i=k;i>=1;i--){
			for (int j=i*c;j<=min((i+1)*c-1,n);j++){
				big.push(a[j]);
			}
			ans+=big.top();
			big.pop();
		}
		printf("%lld\n",ans);
	}
	return 0;
}

J题

还是比较简单的树形DP,我们返回的答案是一个结构体~~~因为答案要求两个。

在树形DP的时候,可以直接求解深度。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define Maxn 100010
#define Maxm 200100
using namespace std;
struct Ans{
	int num,cost;
};
struct Edge {  
    int to, next;
    int len;
}edge[Maxm +10];  
int en, head[Maxn];  
bool vis[Maxn];
inline void add_edge(int u, int v, int len) {  
    edge[en].to = v, edge[en].len = len, edge[en].next = head[u], head[u] = en++;  
}

Ans TreeDP(int t,int deep){
	Ans ans;
	vis[t]=true;
	ans.num=0;ans.cost=0;
	for (int p=head[t];p!=-1;p=edge[p].next){
		int to=edge[p].to,len=edge[p].len;
		if (!vis[to]){
			Ans tmp=TreeDP(to,deep+1);
			if (len==2){
				if (tmp.num==0){
					ans.num+=1;ans.cost+=deep+1;
				}
				else{
					ans.num+=tmp.num;ans.cost+=tmp.cost;
				}
			}
			else{
				ans.num+=tmp.num;ans.cost+=tmp.cost;
			}
		}
	}
	return ans;
}
int main(){
	int n,u,v,len;
	while (~scanf("%d",&n)){
		en=0;
		memset(head,-1,sizeof(head));
		for (int i=1;i<=n-1;i++){
			scanf("%d%d%d",&u,&v,&len);
			add_edge(u,v,len);
			add_edge(v,u,len);
		}
		memset(vis,false,sizeof(vis));
		Ans ans=TreeDP(1,0);
		printf("%d %d\n",ans.num,ans.cost);
	}
	return 0;
}

H题

Angel Beat!

题目大意,我们要去宿舍里找天使,每个宿舍有个编号,从1到n,a宿舍能到b宿舍,当且仅当 a宿舍的编号中 插入一个数字之后能变成 b宿舍的编号。现在假设 a能到b,b能到c,如果我们查找了b宿舍,那么a,c宿舍都不能查找了。题目问:我们最多能查找多少宿舍。(1<=n<=100000)

分析:神题。


A题

题目看到一半没看懂就放弃了= =

题目大意:给出一个N*M的矩阵,我们最少用多少1*L(L为任意长度)的木板来覆盖所有的‘#’,木板之间不能重叠,且 不能覆盖草地。

4 4
#.#.
.###
###.
..#.

题目给出做法:网络流。我暂时没太想明白,欢迎和我交流。


C题
数位dp。
1.数字总绝对不含14.    2.数字和能被14整除    3.数字本身能被14整除。
满足  1并且 满足2或者3的数字  叫做幸运数。求  a到b 之内所有幸运数的平方和。

平方和  是我自己没分析出来。加油!

G题
看起来好复杂,pass。...

I题
求三个字符串中 含有多少种相同的子串(不要求连续)


K题
求题目所要求的第k个排列。
搜索,神剪枝。剪枝使用到了二分匹配0.0


总结,4个小时做完5个题目之后,后边的题目就切不动了...

下次一定会更加优秀!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值