日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NOIP2017提高组模拟赛4 (总结)

發布時間:2024/3/13 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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之間連通。
否則不連通。

#include<cstdio> #include<algorithm> #include<cstring>#define imax(a,b) ((a>b)?(a):(b)) #define imin(a,b) ((a<b)?(a):(b))typedef long long ll;using namespace std;const int mm=500100; const int nn=100100; int N,E,Q,dt,TN; bool vis[nn]; int ti[nn],low[nn]; int ne[mm<<1],to[mm<<1],h[nn],tt; int f[nn][20];void addedge(int a,int b) {to[++tt]=b; ne[tt]=h[a]; h[a]=tt;to[++tt]=a; ne[tt]=h[b]; h[b]=tt; }void dfs(int x,int fa) {f[x][0]=fa;ti[x]=low[x]=++dt; vis[x]=1;for(int p=h[x];p;p=ne[p]){int u=to[p];if(u==fa) continue;if(!vis[u]) dfs(u,x);low[x]=imin(low[x],low[u]);} }int lca(int a,int b) {if(a==b) return a;if(ti[a]<ti[b]) swap(a,b);for(int i=TN;i>=0;i--)if(ti[f[a][i]]>ti[b]) a=f[a][i];return (f[a][0]); }int mingo(int a,int b) {for(int i=TN;i>=0;i--)if(ti[f[a][i]]>ti[b]) a=f[a][i];return a; }bool judge(int u,int v,int a) {int w=lca(u,v);int x=lca(u,a);int y=lca(v,a);if(x!=a) swap(x,y);return (x==a && y==w); }int main() {freopen("b.in","r",stdin);freopen("b.out","w",stdout);scanf("%d%d",&N,&E); tt=1;for(int i=1;i<=E;i++){int A,B; scanf("%d %d",&A,&B);addedge(A,B);}ti[0]=low[0]=0; dt=0; dfs(1,0);f[1][0]=1; TN=0;for(int i=1;(1<<(i-1))<N;i++){TN++;for(int j=1;j<=N;j++)f[j][i]=f[f[j][i-1]][i-1];}scanf("%d",&Q);for(int i=1;i<=Q;i++){int ww,a,b,c,d;scanf("%d",&ww);if(ww==1){scanf("%d%d%d%d",&a,&b,&c,&d);if(ti[a]<ti[b]) swap(a,b);if(ti[c]<ti[d]) swap(c,d);if(judge(a,b,c) && judge(a,b,d)){if(low[c]<=ti[d]) printf("yes\n"); else printf("no\n");} else printf("yes\n");} elseif(ww==2){scanf("%d%d%d",&a,&b,&c);if(ti[a]<ti[b]) swap(a,b);if(judge(a,b,c)){if(lca(a,b)==c){int xx=mingo(a,c),yy=mingo(b,c);if(low[xx]<ti[c] && low[yy]<ti[c]) printf("yes\n"); else printf("no\n");} else{int dp=0;if(lca(a,c)==c) dp=a; else dp=b;int xx=mingo(dp,c);if(low[xx]<ti[c]) printf("yes\n"); else printf("no\n");}} else printf("yes\n");}}return 0; }

第三題 圓桌會議

有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 (总结)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。