NOIP2017提高组模拟赛4 (总结)
生活随笔
收集整理的這篇文章主要介紹了
NOIP2017提高组模拟赛4 (总结)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
NOIP2017提高組模擬賽4 (總結)
第一題 約數
設K是一個正整數,設X是K的約數,且X不等于1也不等于K. 加了X后,K的值就變大了,你可以重復上面的步驟。例如K= 4,我們可以用上面的規則產生所有的非素數. 可以通過5次變化得到。 24: 4->6->8->12->18->24.現在給你兩個整數N 和 M, 求最少需要多少次變化才能到從 N 變到 M. 如果沒法從N變到M,輸出-1.這道題就是很簡單的bfs,可以觀察到n變化到m是近似成倍增長的。其實從最小到最大的變化也就只有30次而已。 #include<cstdio> #include<algorithm> #include<cmath>typedef long long ll;using namespace std;const int maxl=100; const int oo=1e9; const int N=100000; int T,n,m; int op[N+10],ct,ch,f[N+10]; bool uss[N+10];int main() {freopen("a.in","r",stdin);freopen("a.out","w",stdout);scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i=1;i<=N;i++) f[i]=oo,uss[i]=0;f[n]=0; ct=ch=1; op[ct]=n;while(ch<=ct){if(op[ch]<m && f[op[ch]]<maxl){int i=floor(sqrt(op[ch]));i=(m<op[ch]+i)?m-op[ch]:i;for(;i>=2;i--){if(op[ch]%i==0){if(op[ch]+i<=m && f[op[ch]]+1<f[op[ch]+i]){if(!uss[op[ch]+i]) op[++ct]=op[ch]+i,uss[op[ch]+i]=1;f[op[ch]+i]=f[op[ch]]+1;//printf("%d %d -> %d %d\n",op[ch],f[op[ch]],op[ch]+i,f[op[ch]+i]);}if(i*i!=op[ct]){int yu=op[ch]+op[ch]/i;if(yu<=m && f[op[ch]]+1<f[yu]){if(!uss[yu]) op[++ct]=yu,uss[yu]=1;f[yu]=f[op[ch]]+1;//printf("%d %d -> %d %d\n",op[ch],f[op[ch]],yu,f[yu]);}}}}}uss[op[ch]]=0;ch++;}printf("%d\n",(f[m]!=oo)?f[m]:-1);}return 0; }第二題 警察與小偷
為幫助捕獲在逃的犯人, 警局引進了一套新計算機系統. 系統覆蓋了N 個城市,有E條雙向的道路。城市標號為1 到N. 犯人經常從一個城市逃到另外一個城市. 所以警察想知道應該在哪里設置障礙去抓犯人.計算機系統需要回答下面兩種類型的問題: 1. 考慮城市A 、B; 如果把連接城市G1和G2的那條公路切斷,逃犯還能從城市A逃到城市B嗎? 2. 考慮三個城市A、B 、C. 如果把城市C封鎖(則不能從其他進入城市C),逃犯還能從城市A逃到城市B嗎? 你的任務是幫計算機系統回答這些提問。(一開始,任意兩個城市都是可以相互到達的).這是一道好題,數據很大,但邊是雙向的,只是刪一條邊或一個點,而且保證了點兩兩之間是連通的。(這些很重要)那么,可以從dfs序入手,dfs序是一棵樹,其中會有返祖邊。(如圖)
那我們只需要判斷刪掉的點或邊是否在u到v的路徑上,不在的話,刪了也沒用。(用三次lca處理)。
如果刪的是邊,判斷邊的左右端點是否為一個塊,(dfn[a]>dfn[b] 且 low[a]≤dfn[b])是的話,刪了還是u,v保持連通的,否則u,v不連通,(必經路被刪)
如果刪的是點c。lca---u,v的公共祖先
若c在u->lca的路徑上,則更新uminlow(能到達的最早的點)。
若c在v->lca的路徑上,則更新vminlow(能到達的最早的點)。
判斷uminlow和vminlow都小于c就保證了u,v之間連通。
否則不連通。
第三題 圓桌會議
有N個人順時針圍在一圓桌上開會,他們對身高很敏感. 因此決定想使得任意相鄰的兩人的身高差距最大值最小. 如果答案不唯一,輸出字典序最小的排列,指的是身高的排列.一道貪心的題目。假設不是一個環,而是一條鏈,那該怎么做?很顯然,低-高-低這類是不可能的,因為低-低-高肯定比它更優。是環的話,最低-最高這肯定是不行的,因為需要最大的最小。可以考慮數列拆成兩部分(排序后按A5-A3-A1-A2-A4-A6這樣排)。這樣是最優的,詳細證明如下:A5-A3-A1-A2-A4-A6,假設A4-A6最大,可以改得更優,A5移過來,變成A3-A1-A2-A4-A5-A6,那么A3-A6比A4-A6跟大,答案肯定不會優。其他情況也差不多。Ai和Ai+1之間肯定改不了(-_-|| 顯然的)。字典序怎么辦?先求出minans,然后放A1,在右側放A2,判斷A4和當前頭的距離是否合法(小于等于minans),不合法的話A3只能放在頭的左側作為新的頭(不合法的話,再將A3放在右側的話,A4就沒法放了 放左或放右都會使最大距離大于minans),合法的話就將A3放在右側,以此類推。 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>#define imax(a,b) ((a>b)?(a):(b))typedef long long ll;using namespace std;bool cmp(int a,int b) { return (a<b); }int ng,n,d[60],ans,p[60]; int ya[60],yb[60],l1,l2;int main() {freopen("c.in","r",stdin);freopen("c.out","w",stdout);scanf("%d",&ng);while(ng--){scanf("%d",&n); ans=0;for(int i=1;i<=n;i++) scanf("%d",&d[i]);sort(d+1,d+1+n);int w=(n+1)>>1,q=1,cc=w;p[w]=d[1];for(int i=2;i<=n;i++){if((i&1)==0) w+=q; else w-=q;p[w]=d[i];q++;}ans=abs(p[1]-p[n]);for(int i=2;i<=n;i++) ans=imax(ans,abs(p[i]-p[i-1]));l1=1; l2=1;ya[1]=d[1]; yb[1]=d[1];for(int i=2;i<=n;i++){if(abs(d[i+1]-yb[l2])>ans) yb[++l2]=d[i]; else ya[++l1]=d[i];}for(int i=1;i<=l1;i++) printf("%d ",ya[i]);for(int i=l2;i>=2;i--) printf("%d ",yb[i]); printf("\n");}return 0; }考的不怎么好,沒狀態,最后一題想出來但字典序問題沒搞好。爭取在每一次考試中都能不斷進步吧!
超越自己,讓自己變得更好 ------------加油,努力
轉載于:https://www.cnblogs.com/kekxy/p/7526108.html
總結
以上是生活随笔為你收集整理的NOIP2017提高组模拟赛4 (总结)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle、MySQL、SqlServ
- 下一篇: C# thread和delegate l