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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

51nod百度之星2016练习赛

發布時間:2024/4/17 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 51nod百度之星2016练习赛 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天看了看51nod發現有這樣一個練習賽,就做了做。因為實力太弱想不出E題,各位神犇勿D。

(5.26UPD:E題想粗來了)

A?區間交

不難發現若干線段[li,ri]的交就是[max(li),min(ri)],那么我們考慮枚舉min(ri),將ri>=min(ri)的區間按順序加入,這時我們顯然應該選第k小的li來更新答案。這些操作用個堆就可以輕松維護了。

時間復雜度為O(NlogN)。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() {if(head==tail) {int l=fread(buffer,1,BufferSize,stdin);tail=(head=buffer)+l;}return *head++; } inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } typedef long long ll; const int maxn=100010; int n,k,m; struct Line {int l,r;bool operator < (const Line& ths) const {return r>ths.r;} }A[maxn]; priority_queue<int> Q; ll S[maxn]; int main() {n=read();k=read();m=read();rep(i,1,n) S[i]=S[i-1]+read();rep(i,1,m) A[i].l=read(),A[i].r=read();sort(A+1,A+m+1);rep(i,1,k) Q.push(A[i].l);ll ans=max(0ll,S[A[k].r]-S[Q.top()-1]);rep(i,k+1,m) {if(Q.top()>A[i].l) Q.pop(),Q.push(A[i].l);ans=max(ans,S[A[i].r]-S[Q.top()-1]);}printf("%lld\n",ans);return 0; }

B?中位數計數

開始沒有看清題目:“求出每個數在多少個包含其的區間中是中位數”,所以我們只需考慮長度為奇數的區間就可以了。

那么對于每個數x求出答案就是一個經典問題了,<x的Ai設為-1,=x的Ai設為0,>x的Ai設為1,然后求一下有多少區間和為0就可以了。

時間復雜度為O(N^2)。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() {if(head==tail) {int l=fread(buffer,1,BufferSize,stdin);tail=(head=buffer)+l;}return *head++; } inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } const int maxn=8010; int n,A[maxn],B[maxn],S[maxn*2]; int main() {n=read();rep(i,1,n) A[i]=read();rep(i,1,n) {rep(j,1,n) {if(A[i]==A[j]) B[j]=0;else if(A[i]>A[j]) B[j]=1;else B[j]=-1;B[j]+=B[j-1];}int ans=0;memset(S,0,sizeof(S));for(int j=1;j<=n;j+=2) {S[B[j-1]+n]++;ans+=S[B[j]+n];}memset(S,0,sizeof(S));for(int j=2;j<=n;j+=2) {S[B[j-1]+n]++;ans+=S[B[j]+n];}printf("%d%c",ans,i==n?'\n':' ');}return 0; }

C?瞬間移動

f[i][j]=ΣΣf[i`][j`](i`>=i+1,j`>=j+1)

f[i+1][j]=ΣΣf[i`][j`](i`>i+1,j`>=j+1)

f[i][j+1]=ΣΣf[i`][j`](i`>=i+1,j`>j+1)

f[i][j]=f[i+1][j]+f[i][j+1]-{ΣΣf[i`][j`](i`>i+1,j`>j+1)}+f[i+1][j+1]

? ? ? ? =f[i+1][j]+f[i][j+1]

然后坐標變換一下就轉化成f[i][j]=f[i-1][j-1]+f[i-1][j]了,答案即為C(n+m-4,n-2)。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() {if(head==tail) {int l=fread(buffer,1,BufferSize,stdin);tail=(head=buffer)+l;}return *head++; } inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } typedef long long ll; const int maxn=1010; const int mod=1000000007; ll pow(ll n,int m) {ll ans=1;for(;m;m>>=1,(n*=n)%=mod) if(m&1) (ans*=n)%=mod;return ans;} int f[maxn][maxn]; ll C(int n,int m) {ll ans1=1,ans2=1;rep(i,n-m+1,n) (ans1*=i)%=mod; rep(i,1,m) (ans2*=i)%=mod;return ans1*pow(ans2,mod-2)%mod; } int main() {int n=read()-1,m=read()-1;printf("%lld\n",C(n+m-2,n-1));return 0; }

D?區間的價值

對隨機數據有這樣一個性質:如果從位置1向后跳,每次跳到下一個值嚴格比這一個大的位置,期望跳O(logn)次就會終止。

所以我們可以枚舉左端點,模擬右端點的跳躍同時維護當前[l,r]的Ai的最大值mx與最小值mn,用二分套ST表就可以O(logn)計算出下一個mx或mn值改變的位置,在這個區間內答案是不變的,只要在區間打上一個max標記就可以了,用線段樹可以做到O(logn),因為總跳越次數為O(nlogn),時間復雜度為O(nlog^2n)。

但這道題有點卡常數,進一步觀察得到答案是隨長度不增的,所以更新答案時只需要前綴打個標記就行了,這樣就可以省掉線段樹的常數了。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() {if(head==tail) {int l=fread(buffer,1,BufferSize,stdin);tail=(head=buffer)+l;}return *head++; } inline int read() {int x=0,f=1;char c=Getchar();for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;for(;isdigit(c);c=Getchar()) x=x*10+c-'0';return x*f; } typedef long long ll; const int maxn=100010; const int inf=2000000000; int n,A[maxn]; int Log[maxn],minv[20][maxn],maxv[20][maxn]; void init() {Log[0]=-1;rep(i,1,n+1) Log[i]=Log[i>>1]+1;rep(i,1,n) minv[0][i]=maxv[0][i]=A[i];minv[0][n+1]=-inf;maxv[0][n+1]=inf;for(int j=1;(1<<j)<=n+1;j++)for(int i=1;i+(1<<j)<=n+2;i++) {minv[j][i]=min(minv[j-1][i],minv[j-1][i+(1<<j-1)]);maxv[j][i]=max(maxv[j-1][i],maxv[j-1][i+(1<<j-1)]);} } int query(int l,int r,int t) {int k=Log[r-l+1];if(!t) return min(minv[k][l],minv[k][r-(1<<k)+1]);return max(maxv[k][l],maxv[k][r-(1<<k)+1]); } int getmn(int l,int val) {int r=n+1,mid,p=l;while(l<r) if(query(p,mid=l+r>>1,0)<val) r=mid; else l=mid+1;return l; } int getmx(int l,int val) {int r=n+1,mid,p=l;while(l<r) if(query(p,mid=l+r>>1,1)>val) r=mid; else l=mid+1;return l; } ll ans[maxn]; int main() {n=read();rep(i,1,n) A[i]=read();init();int cnt=0;rep(l,1,n) {int mx=A[l],mn=A[l],r=l;while(r<=n) {int p=min(getmn(r+1,mn),getmx(r+1,mx));cnt++;ans[p-l]=max(ans[p-l],(ll)mx*mn);r=p;mn=min(mn,A[r]);mx=max(mx,A[r]);}}dwn(i,n,1) ans[i]=max(ans[i],ans[i+1]);rep(i,1,n) printf("%lld\n",ans[i]);return 0; }

E?刷題計劃

一般來說,這類二維乘積最小的問題都可以通過類似二維乘積最小生成樹的方法解決。

對于一個代碼量之和=x,無聊值之和=y的方案,我們將(x,y)這個點放到平面直角坐標系上,那么整個問題的答案可以看成一個關于x的函數。

不難證明,最優方案只有可能是下凸殼上的點(用反比例函數)。

那么我們可以使用分治算法來解決這個問題,如果我們已經找到了兩個決策點A、B,且A在B的左上方,我們每次只需找到一個在線段AB下方的凸點P,進一步分析問題可得,我們選與在AB垂線上投影盡量短的向量OP即可。如果找到了我們就可以分治子問題了。

那么這樣的點怎么找呢?因為向量和的內積=向量內積的和,我們將每個物品的價值變成向量(bi,ci)在AB垂線上的射影長度,之后就是經典的背包問題,做一次簡單的DP就可以得到方案了。

時間復雜度為期望O(sqrt(N)*N*M)

#include<cstdio> #include<cstring> #include<cctype> #include<cmath> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) using namespace std; inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } const int maxn=410; const int maxm=810; int n,m,M,A[maxn]; typedef long long ll; struct Point {ll x,y; }; double w[maxn],f[maxn][maxm]; ll ans,B[maxn],C[maxn]; int use[maxn],g[maxn][maxm]; double cal(Point a,Point b) {ll k=a.x*b.x+a.y*b.y;return (double)k/sqrt(b.x*b.x+b.y*b.y); } void print(int i,int j) {if(!i) return;if(g[i][j]) use[i]=1,print(i-1,j-A[i]);else use[i]=0,print(i-1,j); } void work(Point P1,Point P2) {Point k=(Point){P1.y-P2.y,P2.x-P1.x};f[0][0]=0;rep(i,1,M) f[0][i]=1e100;rep(i,1,n) {w[i]=cal((Point){B[i],C[i]},k);rep(j,0,M) {if(j<A[i]||f[i-1][j]<f[i-1][j-A[i]]+w[i]) f[i][j]=f[i-1][j],g[i][j]=0;else f[i][j]=f[i-1][j-A[i]]+w[i],g[i][j]=1;}}int x=m;rep(i,m+1,M) if(f[n][i]<f[n][x]) x=i;print(n,x);ll s1=0,s2=0;rep(i,1,n) if(use[i]) s1+=B[i],s2+=C[i];ans=min(ans,s1*s2);if(P1.x==s1&&P1.y==s2) return;if(P2.x==s1&&P2.y==s2) return;work(P1,(Point){s1,s2});work((Point){s1,s2},P2); } int main() {n=read();m=read();rep(i,1,n) M+=(A[i]=read()),B[i]=read(),C[i]=read();ans=1ll<<60;work((Point){0,1e9},(Point){1e9,0});printf("%lld\n",ans);return 0; }

F?貨物運輸

設傳送站分別設在x和y,且x<y。

考慮二分答案ans,將所有R[i]-L[i]>ans的路線拿出來,那么|L[i]-x|+|R[i]-y|<=ans。

將所有的(L[i],R[i])作為平面的點,那么問題就轉化成在平面中尋找一個點P,滿足P到其他的點的曼哈頓距離均<=ans。

坐標變換一下(將(x,y)變換成(x-y,x+y))將曼哈頓距離轉化成切比雪夫距離,然后直接維護矩形交就行了。

時間復雜度為O(NlogN)。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() {if(head==tail) {int l=fread(buffer,1,BufferSize,stdin);tail=(head=buffer)+l;}return *head++; } inline int read() {int x=0,f=1;char c=Getchar();for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;for(;isdigit(c);c=Getchar()) x=x*10+c-'0';return x*f; } const int maxn=500010; const int inf=1e9; int n,m,L[maxn],R[maxn]; int check(int d) {int x1=-inf,y1=-inf,x2=inf,y2=inf;rep(i,1,m) if(R[i]-L[i]>d) {int X1=L[i]-R[i]-d,Y1=L[i]+R[i]-d,X2=L[i]-R[i]+d,Y2=L[i]+R[i]+d;if(x2<X1||x1>X2) return 0;else x1=max(x1,X1),x2=min(x2,X2);if(y2<Y1||y1>Y2) return 0;else y1=max(y1,Y1),y2=min(y2,Y2);}return 1; } int main() {n=read();m=read();int l=0,r=n,mid;rep(i,1,m) {L[i]=read();R[i]=read();if(L[i]>R[i]) swap(L[i],R[i]);}while(l<r) if(check(mid=l+r>>1)) r=mid; else l=mid+1;printf("%d\n",l);return 0; }

G?帶可選字符的多字符串匹配

比較坑的是模式串可能有空格。

打個暴力結果不小心A了(不知所措),求神犇題解。。。

#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() {int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f; } typedef long long ll; const int maxn=2100010; char s[maxn],tmp[310]; int n; ll A[610]; int id(char c) {if(isdigit(c)) return c-'0';if(c>='a'&&c<='z') return c-'a'+10;if(c>='A'&&c<='Z') return c-'A'+36;return 63; } int main() {char c=getchar();int m=0;while(c!='\n') s[++m]=c,c=getchar();n=read();rep(i,1,n) {int k=read();if(k) scanf("%s",tmp);rep(j,0,k-1) A[i]|=1ll<<id(tmp[j]);}int is=0;for(int i=1;s[i+n-1];i++) {int ok=1;rep(j,1,n) if(!(A[j]>>id(s[i+j-1])&1)) {ok=0;break;}if(ok) printf("%d\n",i),is=1; }if(!is) puts("NULL");return 0; }

  

轉載于:https://www.cnblogs.com/wzj-is-a-juruo/p/5528249.html

總結

以上是生活随笔為你收集整理的51nod百度之星2016练习赛的全部內容,希望文章能夠幫你解決所遇到的問題。

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