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個題目之後,後邊的題目就切不動了...

下次一定會更加優秀!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章