hihocoder 編程練習賽79(只有123, 4正在更新)

hihocoder 編程練習賽79

目錄

hihocoder 編程練習賽79

題目1 : 字母去重

1.題是什麼?

2.思路

3.ac代碼

題目2 : D級上司

1.題是什麼?

2.思路

3.ac代碼

題目3 : 數組的F值

1.題是什麼?

2.思路

(1)INS操作

(2).DEL操作

3.ac代碼


 

題目1 : 字母去重

時間限制:10000ms

單點時限:1000ms

內存限制:256MB

描述

給定一個字符串S,每次操作你可以將其中任意一個字符修改成其他任意字符。

請你計算最少需要多少次操作,才能使得S中不存在兩個相鄰的相同字符。

輸入

只包含小寫字母的字符串S。  

1 ≤ |S| ≤ 100000

輸出

一個整數代表答案

樣例輸入

aab

樣例輸出

1

1.題是什麼?

    給你一個字符串,每次操作可以改任意一個字符爲任意字符,最少多少次操作,可以使字符串不存在相鄰相同字符

2.思路

    貪心的從左到右的改,唯一一個坑是對於字符串aaa你可以將中間的a改成b,這樣只需要一次操作就能完成目的,如果你的程序能過掉aaa這個樣例,就能ac了.故而我們貪心的方法應該是判斷這個字符和前一個字符是否相同.

3.ac代碼

#include <stdio.h>

void solve(){
	char a[100005];
	scanf("%s",&a);
	int pos=1,ans=0;
	while(a[pos]){
		if(a[pos]==a[pos-1]){
			a[pos]='?';
			ans++;
		}
		pos++;
	}
	printf("%d\n",ans);
}


int main(){
	solve();
	return 0;
}

 

題目2 : D級上司

時間限制:10000ms

單點時限:1000ms

內存限制:256MB

描述

H公司一共有N名員工,編號爲1~N,其中CEO的編號是1。除了CEO之外,每名員工都恰好有唯一的直接上司;N名員工形成了一個樹形結構。  

我們定義X的1級上司是他的直接上司,2級上司是他上司的上司,以此類推……  

請你找出每名員工的D級上司是誰。

輸入

第一行包含2個整數N和D。  

以下N-1行每行包含一個整數,依次代表編號是2-N的員工的直接上司的編號。  

對於50%的數據,1 ≤ N, D ≤ 10000  

對於100%的數據,1 ≤ N, D ≤ 100000

輸出

依次輸出1~N的D級上司的編號,每個一行。如果某員工沒有D級上司,輸出-1。

樣例輸入

5 2   
1  
1  
3  
3

樣例輸出

-1  
-1  
-1  
1  
1

1.題是什麼?

    給你n-1個員工的直接隸屬關係,即爲每個員工唯一的直接上司,你要輸出的是每個員工的d級上司.

2.思路

    這是一個樹型關係,故而想到dfs路徑保存來解決,至於樹形關係的存儲使用vector實現的鄰接表,這樣dfs到每個員工時通過沿途保存的路徑我能夠知道他的所有的上級間接上司,自然也能知道是否有d級,是誰,

    複雜度方面:

        空間上路徑數組只需要最多maxn,vector雖然大小maxn,可是由於是樹,相當於稀疏圖,vector也不會爆,遞歸的深度在極限數據下可能達到maxn造成爆棧,然而我交上去試了一下ac了,故而不對此問題進行優化

        時間上每個結點的處理複雜度爲1,每個結點也只會處理一次,故時間不足爲慮.

3.ac代碼

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;

const int maxn=100005;
vector<int> v[maxn];
int path[maxn],deep;
int ans[maxn];
void dfs(int serial,int d){
	if(deep<d) ans[serial]=-1;
	else ans[serial]=path[deep-d];
	path[deep++]=serial;
	int size=v[serial].size();
	for(int i=0;i<size;i++) dfs(v[serial][i],d); 
	deep--;
}

void solve(){
	int n,d;
	scanf("%d%d",&n,&d);
	for(int i=2;i<=n;i++){
		int t;
		scanf("%d",&t);
		v[t].push_back(i);	
	}
	deep=0;
	dfs(1,d);
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]); 
	
}


int main(){
	solve();
	return 0;
}

題目3 : 數組的F值

時間限制:10000ms

單點時限:1000ms

內存限制:256MB

描述

我們定義一個數組A = [A1, A2, ... AN]的F值F(A)是:

將A從小到大排序得到數組B = [B1, B2, ... BN],F(A) = (B2 - B1)2 + (B3 - B2)2 + ... + (BN - BN-1)2    

現在給定一個長度爲N的數組A,然後依次對A進行M項操作。每項操作是以下2種之一:

INS X:插入一個值爲X的元素

DEL X:刪除所有值爲X的元素  

請你計算每次操作之後的F(A)

輸入

第一行包含兩個整數N和M。  

第二行包含N個整數A1, A2, ... AN。  

以下M行每行一個操作。  

對於50%的數據,1 ≤ N, M ≤ 1000  

對於100%的數據,1 ≤ N, M ≤ 100000  1 ≤ X, Ai ≤ 100000

輸出

對於每一項操作輸出操作之後的F(A),每個一行。

樣例輸入

5 3  
1 2 4 5 6  
INS 3  
INS 4  
DEL 4

樣例輸出

5  
5  
7

 

1.題是什麼?

    給你n個數字的數組a,讓你將它排序成b數組,然後計算一個fa值,fa=(B2 - B1)^2 + (B3 - B2)^2 + ... + (BN - BN-1)^2,

之後讓你對a數組做m次操作 ,操作可能是以下兩種之一

        INS X:插入一個值爲X的元素

        DEL X:刪除所有值爲X的元素 

    每次操作完了之後輸出此時a數組的fa值.

2.思路

   首先關於fa的求得,我們可以發現對a無論升序還是降序排序得到的答案fa是相同的,故而我採用升序.另外我們從fa公式中會發現重複的值是不改變最終fa值的,我們這裏直接將數據壓入set就好,set會維持升序,還會自動去重.

    然後下面分析兩種操作對fa值的影響:

(1)INS操作

插入值在原set中已存在的情況下:

    下面以在已排序並去重的B set集合1 2 3 5 7中INS 3爲例進行分析

    fa原先爲(2-1)^{2}+(3-2)^{2}+(5-3)^{2}+(7-5)^{2}

    插入3後對於1 2 3 3 5 7 fa爲(2-1)^{2}+(3-2)^{2}+(3-3)^{2}+(5-3)^{2}+(7-5)^{2}

    (3-3)^{2}必然等於0,故而我們發現當插入的x在原set中已存在時是不會改變fa值的,由於重複值是無效的故而我們甚至不用將值插入set.

 

插入值在原set中不存在的情況下:

    下面以在已排序的B set集合1 2 5 7中INS 3爲例進行分析

    fa原先爲(2-1)^{2}+(5-2)^{2}+(7-5)^{2}

    插入3後對於1 2 3 5 7fa爲(2-1)^{2}+(3-2)^{2}+(5-3)^{2}+(7-5)^{2}

    注意細節會發現前後不變,變的僅僅是2 5與2 3 5的fa計算,故而我們對於插入操作僅考慮插入值與其前後值的關係改變就好,假如插入值x前一個值爲lower,後一個值爲upper,fa的改變爲加上(upper-x)^{2}+(x-lower)^{2}-(upper-lower)^{2},這裏需要注意一個細節,就是如果ins的值在序列中是最小值或是最大值怎麼辦,這樣它就可能沒有lower或upper,甚至如果序列爲空,可能兩個都沒有,故而要特殊處理一下,見代碼,

(2).DEL操作

    下面以在已排序並去重的B set集合1 2 3 5 7中DEL 3爲例進行分析(如果del的是不存在的數則可直接輸出fa,進行下一個操作)

     fa原先爲(2-1)^{2}+(3-2)^{2}+(5-3)^{2}+(7-5)^{2}

     刪除3後對於1 2 5 7 fa爲(2-1)^{2}+(5-2)^{2}+(7-5)^{2}

     就是ins原先不存在的值時的逆向,fa的改變自然顯而易見爲加上(upper-lower)^{2}-(upper-x)^{2}-(x-lower)^{2},前面加個負號而已.依然對於是最大值或最小值時特殊處理一下.之後將x從set中真正刪除,保持數據有效性.

後續更新:最開始由於使用數組保存數據使得數據有效性的保持用了n複雜度,導致總複雜度n*n造成tle,現在用set保存數據,由於set底層是由二叉搜索樹實現,對於單個數據的增刪複雜度爲logn,總複雜度nlogn已ac

3.ac代碼

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=100005;

set<ll> s;
set<ll>::iterator ite,ite1,ite2;

void solve(){
	int n,m;
	scanf("%d%d",&n,&m);
	//set的插入操作本身會去重 
	for(int i=0;i<n;i++){
		int t;
		scanf("%d",&t);
		s.insert(t);
	}

	//初始fa 
	ll fa=0;
	ite=s.begin();
	ite1=ite;
	ite2=++ite; 
	while(ite2!=s.end()){
		fa+=(*ite2-*ite1)*(*ite2-*ite1);
		ite1=ite2;
		++ite2;
	}
	
	//操作 
	char order[10];
	ll number;
	for(int i=0;i<m;i++){
		scanf("%s%lld",&order,&number);
		ite=s.find(number);//以logn複雜度找到大於等於number的第一個數的位置
		if(!strcmp(order,"INS")){
			if(ite==s.end()){
				s.insert(number); 
				ite=s.find(number);
				ite2=ite;ite2++;//位置加一自然就是正好比number小的數
				ite1=ite;ite1--;//位置減一自然就是正好比number小的數
				if(ite!=s.begin()){
					fa+=(number-*ite1)*(number-*ite1);
					if(ite2!=s.end()){
						fa-=(*ite2-*ite1)*(*ite2-*ite1); 
					}
				}
				if(ite2!=s.end()){
					fa+=(*ite2-number)*(*ite2-number);
				}
			}
		}
		else if(!strcmp(order,"DEL")){
			if(ite!=s.end()){
				ite2=ite,ite2++;//此時number還沒刪除,故而ite此時指向number,需要++纔是正好比number大的數 
				ite1=ite,ite1--;//減一就是 
				if(ite!=s.begin()){
					fa-=(number-*ite1)*(number-*ite1);
					if(ite2!=s.end()){
						fa+=(*ite2-*ite1)*(*ite2-*ite1); 
					}
				}
				if(ite2!=s.end()){
					fa-=(*ite2-number)*(*ite2-number);
				}
				s.erase(number);
			}
		}
		printf("%lld\n",fa);
	}
}

int main(){
	solve();
	return 0;
}

 

 

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