NOIP模擬題彙總(加厚版)
$NOIP$模擬題彙總(加厚版)
T1 string
描述
有一個僅由 '0' 和 '1' 組成的字串 $A$,可以對其執行下列兩個操作:
- 刪除 $A$中的第一個字元;
- 若 $A$中 '1' 出現的次數為奇數,則在 $A$ 的末尾插入 '1',否則在 $A$ 的末尾插入 '0'.
現在給出一個同樣僅由 '0' 和 '1' 組成的字串 $B$,請你判斷 $A$ 能否在任意多次操作後轉化為 $B$。
輸入
輸入檔案第一行一個正整數 $T$,表示有 $T$ 組資料需要進行判斷。
接下來依次輸入 $T$ 組資料,每組資料有兩行,其中第一行包含一個字串 $A$,第二行包含一個字串 $B$。
輸出
輸出共 $T$ 行,對應 $T$ 組詢問。若第 $i$ 組資料中 $A$串可以轉化為 $B$ 串則輸出 "YES";否則輸出 "NO"。
輸入樣例 1
輸出樣例 1
YES NO
提示
對於 $20%$ 的資料,$n$≤$10$, $T$=$3$
對於 $50%$ 的資料,$n$≤$1000$, $T$≤$20$。
對於 $100%$ 的資料,$n$≤$10^6$, $T$≤$50$。
題解
一道水題,
。
自己手推幾組樣例,就會發現一個規律:ans只與01串中$1$的個數有關
因為你可以講前面的數刪掉加到後面形成組合;
所以如果$A$中$1$的個數大於等於$B$中$1$的個數則輸出$YES$,否則輸出$NO$;
但是要注意若$A$中$1$的個數為奇數要拿$($$A$中$1$的個數+1$)$與$B$中$1$的個數比較即可;
code:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cctype> #define ll long long #define R register using namespace std; template<typename T>inline void read(T &a){ char c=getchar();T x=0,f=1; while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} a=f*x; } char a[N],b[N]; int lena,lenb,A,B,t; int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); read(t); while(t--){ A=0;B=0; scanf("%s%s",(a+1),(b+1)); lena=strlen(a+1); lenb=strlen(b+1); for(R int i=1;i<=lena;i++) if(a[i]=='1')A++; for(R int i=1;i<=lenb;i++) if(b[i]=='1')B++; if(A&1)A++; if(A>=B)printf("YES\n"); else printf("NO\n"); } return 0; }
T2 glide
描述
大森林中茂盛地生長著 $N$ 棵樹,從 $1$ 到 $N$ 編號,第 $i$ 棵樹的高度是 $H_i$,住在這片森林裡的飛鼠 Makik 可以在樹與樹之間滑翔。
有 $M$ 組樹能供 $Makik$在其間滑翔,在每組樹間滑翔的時間是固定的。滑翔時,$Makik$ 每秒會下落 $1$ 米,即當 $Makik$ 當前位置距離地面 $h$ 米時,它經過 $t$ 秒的滑翔後會落到距離地面 $h-t$米的高度上。但若$h-t$ 小於 $0$ 或比要到達的樹高還要大,則 $Makik$ 不能進行這次滑行。
除滑翔外,$Makik$ 還可以沿著一棵樹爬上爬下,每向上或向下移動 $1$ 米均需花費 $1$ 秒的時間。現在,$Makik$ 想要從第 $1$ 棵樹上高度為 $X$ 米的位置移動到第 $N$ 棵樹的頂端(高度為 $H_N$ 的位置),請你幫它算一算最少要花費多少秒的時間。
輸入
輸入檔案第一行包含三個整數 $N$,$M$,$X$,分別表示樹的數量、能供 $Makik$ 在其間滑翔的樹的組數和 $Makik$ 的初始高度。
下面 $N$ 行,其中第 $i$ 行包含一個整數,表示第 $i$ 棵樹的高度 $H_i$。
接下來 $M$ 行,其中 $j$ 行包含三個整數 $A_j$,$B_j$,$T_j$($A_j$$\neq$ $B_j$),表示 $Makik$ 可以在第 $A_j$ 棵樹和第 $B_j$ 棵樹間相互滑行,每次滑行的時間是 $T_j$ 秒。資料保證每一組樹都不會被多次給出。
輸出
輸出一行一個整數,表示 $Makik$ 到達第 $N$ 棵樹所至少要花費的秒數。如果不能到達,輸出 $-1$。
題解
我這道題在最短路上搞了一些操作,感覺想貪心,感覺不對,
;
輸入樣例 1
輸出樣例 1
提示
樣例說明:
先沿第 $1$ 棵樹向上爬 $50$ 米,再依次滑翔到第 $2$ 棵、第 $4$ 棵、第 $5$ 棵樹上,最後沿第 $5$ 棵樹向上爬 $10$ 米。
資料規模與約定
對於 $30%$ 的資料,$N\leq 1000$, $M\leq 3000$, $H_i\leq 100$, $T_j\leq 100$。
對於另外 $30%$ 的資料,$X=0$。
對於 $100 %$ 的資料,$2\leq N\leq 100000$, $1\leq M\leq 300000$, $1\leq H_i\leq 10^9$, $1\leq T_j\leq 10^9$, $0\leq X\leq H_1$。
題解
std講的思路:
一直跑$SPFA$(或$Dij$堆優化),最後$ans$=(地底下的距離乘以2+地上的距離);
std’s code:
#include <bits/stdc++.h> using namespace std; #define N 100005 #define M 600005 #define _inf -4557430888798830400ll int n, m, h[N]; long long X, d[N]; priority_queue<pair<long long, int> > q; int head[N]; struct graph { int next, to, val; graph() {} graph(int _next, int _to, int _val) : next(_next), to(_to), val(_val) {} } edge[M]; inline void add(int x, int y, int z) { static int cnt = 0; edge[++cnt] = graph(head[x], y, z); head[x] = cnt; } void spfa(int s) { memset(d, 0xc0, sizeof d); d[s] = X; q.push(make_pair(X, s)); while (!q.empty()) { int x = q.top().second; long long y = q.top().first; q.pop(); if (y != d[x]) continue; for (int i = head[x]; i; i = edge[i].next) if (edge[i].val <= h[x]) if (d[edge[i].to] < min(y - edge[i].val, 1ll * h[edge[i].to])) d[edge[i].to] = min(y - edge[i].val, 1ll * h[edge[i].to]), q.push(make_pair(d[edge[i].to], edge[i].to)); } } int main() { cin >> n >> m >> X; for (int i = 1; i <= n; ++i) scanf("%d", &h[i]); for (int x, y, z, i = 1; i <= m; ++i) scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z); spfa(1); if (d[n] == _inf) cout << -1 << endl; else cout << (X - d[n]) * 2 - X + h[n] << endl; return 0; }
我的思路:
老師的思路中細節比較少但可能不太好想,但我的寫法比較好理解 $(/ω\ )$。
我的思路就是在$SPFA$中模擬一個$H$陣列,$H_i$表示跑最短路時,在$i$點時的高度(就是你以最短路去走到$i$點時的高度)。
我認為就是在最短路時模擬......(細節比較多)
my code:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cctype> #include<queue> #define ll long long #define R register #define N 300005 #define INF 0x7fffffffffLL using namespace std; template<typename T>inline void read(T &a){ char c=getchar();T x=0,f=1; while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} a=f*x; } int n,m,x,head[N],tot,flag,h[N],H[N],vis[N],u,v,w; ll dist[N]; inline int abss(R int x){return x<0?-x:x;} struct node{ int nex,to,dis; }edge[N<<1]; inline void add(R int u,R int v,R int w){ edge[++tot].nex=head[u]; edge[tot].to=v; edge[tot].dis=w; head[u]=tot; } inline void spfa(R int s){ queue<int>q; for(R int i=1;i<=n;i++)dist[i]=INF; q.push(s);vis[s]=1;dist[s]=0;H[s]=x; while(!q.empty()){ R int x=q.front();q.pop();vis[x]=0; for(R int i=head[x];i;i=edge[i].nex){ R int xx=edge[i].to; -------------//下面是模擬判斷 細節比較多//-------------------------------------------------------- R int now=0;//now是模擬你需要爬多少步正數為向上爬負數為想下爬 if(H[x]-edge[i].dis<0)now=(edge[i].dis-H[x]);//以當前高度跳到要更新的點會跳到地下 else if(H[x]-edge[i].dis>h[xx])now=(-1)*(H[x]-edge[i].dis-h[xx]);//跳到天上 if(H[x]+now>h[x]||H[x]+now<0)continue;//判斷當前能不能爬(不能爬到地下或天上) if(dist[xx]>dist[x]+edge[i].dis+abss(now)){ dist[xx]=dist[x]+edge[i].dis+abss(now); H[xx]=H[x]+now-edge[i].dis;// 實時更新H陣列 if(!vis[xx]){ vis[xx]=1; q.push(xx); } } } } } int main(){ freopen("glide.in","r",stdin); freopen("glide.out","w",stdout); read(n);read(m);read(x); for(R int i=1;i<=n;i++)read(h[i]); for(R int i=1;i<=m;i++){ read(u);read(v);read(w); add(u,v,w);add(v,u,w); } spfa(1); if(dist[n]==INF)printf("-1\n"); else printf("%lld\n",dist[n]+h[n]-H[n]);//因為題中說要爬到第n棵樹的樹頂 return 0; }