1. 程式人生 > >NOIP2007提高組題解

NOIP2007提高組題解

T1:統計數字

考察知識:快速排序,map的基本操作

演算法難度:XX || X 實現難度:XX || X+

分析:如果用快排的話,要用分治思想,難度稍微大一些,用map就是基本操作,難度不大

如果追求速度可以寫一個快速輸入函式,但是注意輸入是否有負數

map版程式碼(含快速輸入):

#include<cstdio>
#include<map>
#include<cctype>
using namespace std;
int T;
char ch;
void scan(int& in_){
    T=1,ch=getchar();
    while(!isdigit(ch)) {
        if(ch=='-') T=-1;
        ch=getchar();
    } in_=0;
    while(isdigit(ch)) in_=in_*10+ch-'0',ch=getchar();
    in_*=T;
}
map<int,int>mp;
map<int,int>::iterator it;
int n,k;
int main(){
    scan(n);
    while(n--) scan(k),mp[k]++;
    for(it=mp.begin();it!=mp.end();it++)
        printf("%d %d\n",it->first,it->second);
    return 0;
}

考察知識:字串,模擬

演算法難度:XX 實現難度:XXX

分析:按照題目說的來就可以了,但是要注意審題,要考慮全面,如:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
char str[105];
int p1,p2,p3;
int main(){
	scanf("%d%d%d",&p1,&p2,&p3);
	scanf("%s",str);
	for(int i=0;str[i]!='\0';i++)
	if(str[i]=='-'&&i&&str[i+1]!='\0'&&str[i-1]<str[i+1]){//條件要考慮全 
		if((isalpha(str[i+1])^isalpha(str[i-1]))||
		str[i+1]=='-'||str[i-1]=='-')//注意異或 
		{putchar('-');continue;}
		if(p3==1){
			for(int j=str[i-1]+1;j<str[i+1];j++)
			  for(int k=1;k<=p2;k++)
			  	if(p1==1) putchar(tolower(j));
			    else if(p1==2) putchar(toupper(j));
			    else putchar('*');
		}else{
			for(int j=str[i+1]-1;j>str[i-1];j--)
			  for(int k=1;k<=p2;k++)
			  	if(p1==1) putchar(tolower(j));
			    else if(p1==2) putchar(toupper(j));
			    else putchar('*');
		}
	}
	else putchar(str[i]);
	return 0;
}

考察知識:高精度,區間型動態規劃

演算法難度:XX 實現難度:XXX

分析:

讀懂題意後我們發現我們可以把矩陣拆分成n排,每排m個元素的序列,然後針對每一排序列用動態規劃:

1.定義f(curi,j)表示第cur排序列[i,j]取數的最大值

2.邊界:f(cur,i,i)=a[cur][i]\times 2^m

3.答案ans=\sum_{i=1}^{n}f(i,1,m)

4.狀態轉移方程:f(cur,i,j)=max\begin{Bmatrix} & f(cur,i+1,j)+a[cur][i]\times2^m^-^j^+^i & \\ & f(cur,i,j-1)+a[cur][j]\times2^m^-^j^+^i & \end{Bmatrix}

因為最後的答案很大,使用要用高精度

程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct bign{
    int a[200],len;
    bign(){a[0]=0,len=1;memset(a,0,sizeof(a));}
    void get_v(int v){
        bign(); if(!v) return; len=0;
        while(v) a[len++]=v%10,v/=10;
    }
    friend bool operator < (bign A,bign B){
        if(A.len!=B.len) return A.len<B.len;
        for(int i=A.len-1;i>=0;i--) if(A.a[i]!=B.a[i])
            return A.a[i]<B.a[i];
        return false;
    }
    friend bign operator + (bign A,bign B){
        bign C;
        C.len=max(A.len,B.len)+1;
        for(int i=0;i<C.len;i++) C.a[i]=A.a[i]+B.a[i];
        for(int i=0;i<C.len;i++) if(C.a[i]>9) C.a[i+1]++,C.a[i]-=10;
        while(C.len>1&&C.a[C.len-1]==0) C.len--;
        return C;
    }
    friend bign operator * (bign A,int x){
        bign C;
        C.len=A.len+20;
        for(int i=0;i<C.len;i++) C.a[i]=A.a[i]*x;
        for(int i=0;i<C.len;i++)
            if(C.a[i]>9) C.a[i+1]+=C.a[i]/10,C.a[i]%=10;
        while(C.a[C.len-1]==0&&C.len>1) C.len--;
        return C;
    }
    friend bign operator * (bign A,bign B){
        bign C;C.len=A.len+B.len;
        for(int i=0;i<A.len;i++)
          for(int j=0;j<B.len;j++)
            C.a[i+j]+=A.a[i]*B.a[j];
        for(int i=0;i<C.len;i++) if(C.a[i]>9) C.a[i+1]+=C.a[i]/10,C.a[i]%=10;
        while(C.len&&C.a[C.len-1]==0) C.len--;
        return C;
    }
    void out(bool Entr=true){
        for(int i=len-1;i>=0;i--) putchar('0'+a[i]);
        if(Entr) putchar('\n');
    }
}ans,f[82][82],b[82];
int n,m,a[100][100];
void calc(int cur){
    for(int i=1;i<=m;i++) f[i][i]=b[m]*a[cur][i];
    for(int len=2;len<=m;len++)
    for(int i=1;i<=m-len+1;i++){
        int j=len+i-1;
        f[i][j]=max(f[i+1][j]+b[m-j+i]*a[cur][i],f[i][j-1]+b[m-j+i]*a[cur][j]);
    }
    ans=ans+f[1][m];
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
    b[0].get_v(1);
    for(int i=1;i<=m;i++) b[i]=b[i-1]+b[i-1];//預處理2^i 
    for(int i=1;i<=n;i++) calc(i);
    ans.out();
    return 0;
}

T4:樹網的核

考察知識:樹的基本知識,樹的直徑,列舉

演算法難度:XXX 實現難度:XXX+

分析:題目有點亂,定義有點多,但是這道題並不難,根據題目的定義列舉可能的端點並計算偏心距就可以了

演算法:

1.先找樹的一條直徑

2.計算直徑上的每一個點到樹的分支(不包含直徑)的最大距離

3.列舉直徑上所有距離小於s的兩點,計算這一段路徑的偏心距,偏心距=max(兩點到直徑端點(不經過這段路徑)的距離,路徑上每一點到這一點所在樹的分支的最大距離)

參考程式碼:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=305;
struct edge{
	int to,l,next;
}e[maxn*2];
int first[maxn],np;
void add(int u,int v,int l){
	e[++np]=(edge){v,l,first[u]};
	first[u]=np;
}
int n,s,A,B,dis[maxn],dis2[maxn],fa[maxn];
bool vis[maxn];
void dfs(int i,int F,int dist,int& R){
	if(dist>dis[R]) R=i;
	dis[i]=dist,fa[i]=F;
	for(int p=first[i];p;p=e[p].next){
		int j=e[p].to;
		if(j==F) continue;
		dfs(j,i,dist+e[p].l,R);
	}
}
void dfs2(int i,int dist,int rt){
	vis[i]=true;
	dis2[rt]=max(dis2[rt],dist);
	for(int p=first[i];p;p=e[p].next){
		int j=e[p].to;
		if(!vis[j]) dfs2(j,dist+e[p].l,rt);
	}
}
void build(){
	int u,v,l;
	scanf("%d%d",&n,&s);
	for(int i=1;i<n;i++){
		scanf("%d%d%d",&u,&v,&l);
		add(u,v,l),add(v,u,l);
	}
	dfs(1,0,0,A=0);//找直徑 
	dfs(A,0,0,B=0);
	for(int i=B;i;i=fa[i]) vis[i]=true;
	for(int i=B;i;i=fa[i]) dfs2(i,0,i);//計算分支最大距離 
}
int ans=0xffffff; 
void solve(){
	for(int i=B;i;i=fa[i])//列舉 
	for(int j=i;j;j=fa[j]) if(dis[i]-dis[j]<=s){ 
		int T=max(dis[j],dis[B]-dis[i]);
		for(int k=i;;k=fa[k]){//計算偏心距 
			T=max(T,dis2[k]);
			if(k==j) break;
		}
		ans=min(ans,T);
	}
	else break;
	printf("%d\n",n==1?0:ans);
}
int main(){
	build();
	solve();
	return 0;
}

相關推薦

NOIP2007 提高 題解

com 想是 設有 最長路徑 區間 space 輸出 als ons 2007 提高組題解 第一題 一開始還想是不是要用哈希表儲存呢,但仔細想了一會兒,那個數據量20W 用個快排序,時間是能過的。所以這道題用個STL的快排,再一個循環統計個數就OK了。但最後交上去評測時

NOIP2007提高題解

T1:統計數字 考察知識:快速排序,map的基本操作 演算法難度:XX || X 實現難度:XX || X+ 分析:如果用快排的話,要用分治思想,難度稍微大一些,用map就是基本操作,難度不大 如果追求速度可以寫一個快速輸入函式,但是注意輸入是否有負數 map版程式

NOIP2018 提高題解

Day1 T1   據說是原題積木大賽,但是考場上蠢了,只會寫資料結構,於是寫了一個線段樹\(+\)堆\(+\)貪心,先選出最小的,然後區間修改,然後把左右兩端區間的最小值丟進堆裡,不停從堆中去最小值更新即可(模擬題) #include <cstdio> #include <cstri

noip2007提高-字串的展開

noip2007提高組-字串的展開 Description 在初賽普及組的“閱讀程式寫結果”的問題中,我們曾給出一個字串展開的例子:如果在輸入的字串中,含有類似於“d-h”或者“4-8”的字串,我們就把它當作一種簡寫,輸出時,用連續遞增的字母獲數字串替代其中的減號,即,將上面兩個子串分別輸出

[NOIP2007提高]字串的展開

題目描述 在初賽普及組的“閱讀程式寫結果”的問題中,我們曾給出一個字串展開的例子:如果在輸入的字串中,含有類似於“d-h”或者“4-8”的字串,我們就把它當作一種簡寫,輸出時,用連續遞增的字母或數字串替代其中的減號,即,將上面兩個子串分別輸出為“defgh”和“45

NOIP2018提高題解(附填數遊戲logn做法)

總體來說,Day1的3題非常水,Day2的難度卻飆升到一定境界了……然後我就GG了…… T1 鋪設道路 題目連結 這道題一眼原題,顯然,如果 d

NOIP2016提高題解

DAY1 T1 很簡單的一個模擬演算法。 從0標號就可以用模,從1標號也可以通過特判(>n就減小於1就加) #include<cstdio> #include<algorithm> #include<cmath

題解【luogup1351 NOIp提高2014 聯合權值】

define 題意 一個點 clu show truct lib ace can 題目鏈接 題意:給定一個無根樹,每個點有一個權值。若兩個點 \(i,j\) 之間距離為\(2\),則有聯合權值 \(w_i \times w_j\)。求所有的聯合權值的和與最大值 分析:

[51Nod]NOIP2018提高省一沖獎班模測訓練(四)翻車記+題解

problem ref sign 二分答案 def pointers 小時 https 奇怪 鏈接 下午5點的時候,突然想起來有這個比賽,看看還有一個小時,打算來AK一下,結果因為最近智商越來越低,翻車了,我還是太菜了。上來10分鐘先切掉了C和A,結果卡在了B題,唉。 A.

題解】[牛客網NOIP賽前集訓營-提高(第五場)]A.同餘方程 位運算

#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const ll mod=998244353; ll m,l1,l2,r1,r2; ll

題解】[牛客網NOIP賽前集訓營-提高(第四場)]C.滅蟲 線性DP+堆優化

題目連結 #include<cstdio> #include<algorithm> #include<queue> using namespace std; const int N=3e3+10; struct node{ int

題解】[牛客網NOIP賽前集訓營-提高(第四場)]B.區間 亂搞

題目連結 #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int MAXN=1e7+10; ll a[MAXN]; int

題解】[牛客網NOIP賽前集訓營-提高(第四場)]A.動態點分治 模擬

題目連結 #include<cstdio> typedef long long ll; int t,find; ll l,r,k,x; int main() { //freopen("in.txt","r",stdin); scanf("%d",&a

題解】[牛客網NOIP賽前集訓營-提高(第三場)]C.急開鎖 博弈論+打表

題目連結 #include<cstdio> typedef long long ll; int t,k,l,r; ll len,f[4000010]; int main() { //freopen("in.txt","r",stdin); scanf("

題解】[牛客網NOIP賽前集訓營-提高(第三場)]B.公平競賽 bfs

題目連結 #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; inline int rea

題解】[牛客網NOIP賽前集訓營-提高(第三場)]A.管道維修 數學期望

題目連結 #include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; #define re regist

題解】[牛客網NOIP賽前集訓營-提高(第二場)]C.集合劃分 狀壓DP

題目連結 看了題解後還是沒寫對,只能去看Komachi大佬咋寫的了。 #include<cstdio> #include<cstring> const int N=18,MX=(1<<18)+5; int n,m,k,ban[N]

題解】[牛客網NOIP賽前集訓營-提高(第二場)]B.分糖果 單調棧優化線性DP+容斥原理

題目連結 #include<cstdio> #define re register typedef long long ll; const int N=1e6+10; const int INF=0x3f3f3f3f; const int mod=1e9

題解】[牛客網NOIP賽前集訓營-提高(第二場)]A.方差 字首和

題目連結 我們把方差公式進行化簡。記 s u m

題解】[牛客網NOIP賽前集訓營-提高(第一場)]C.保護 LCA+線段樹動態開點+線段樹合併

題目連結 ___ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+10; int n,m,hd[N],to