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.邊界:
3.答案
4.狀態轉移方程:
因為最後的答案很大,使用要用高精度
程式碼:
#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