這套題我只會寫第二題。。。我。。。git
T1:給出一個含有向邊和無向邊的混合圖,如何肯定無向邊的方向使得圖中不存在環。保證有解。多解狀況輸出任意解。網絡
=>我往最大流的殘量網絡的方向去想了。。。由於混合圖求歐拉回路用的就是最大流。。。然而什麼都想不出來。。。函數
正解:spa
原圖是個有向無環圖,也就是說是個拓撲圖,若是加完邊後依然是拓撲圖,也就是依然無環。blog
對原圖作拓撲排序,獲得每一個點的入隊時間,加邊的時候把邊定向爲從入隊時間早的點到晚的點,原來的入隊順序就依然成立,就無環了。排序
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #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 clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=1e5+5; const int inf=0x7f7f7f7f; struct edge{ int to;edge *next; };edge es[nmax],*pt=es,*head[nmax]; void add(int u,int v){ pt->to=v;pt->next=head[u];head[u]=pt++; } int q[nmax],in[nmax],qe[nmax]; int main(){ freopen("dizzy.in","r",stdin);freopen("dizzy.out","w",stdout); int n=read(),m=read(),tm=read(),u,v; rep(i,1,m) u=read(),v=read(),add(u,v),in[v]++; int cur=0; rep(i,1,n) if(!in[i]) q[i]=++cur,qe[cur]=i; rep(i,1,cur) qwq(qe[i]) if(!--in[o->to]) q[o->to]=++cur,qe[cur]=o->to; //rep(i,1,n) printf("%d ",q[i]);printf("\n"); rep(i,1,tm) { u=read(),v=read(); if(q[u]>q[v]) swap(u,v); printf("%d %d\n",u,v); } fclose(stdin);fclose(stdout); return 0; } /* 4 5 3 1 2 1 3 2 3 2 4 3 4 */
T2:給出一個500*500的矩陣。可橫着切A刀,豎着切B刀。求最小塊的最大值。get
=>二分答案。。。發現儘可能的弄到函數裏面清晰好多啊T_Tstring
//特別奇怪。輸出ans的時候我寫成了%lld就全WA。。。還覺得沒有什麼關係的TAT #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #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 clr(x,c) memset(x,c,sizeof(x)) #define ll long long int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=505; const int inf=0x7f7f7f7f; int a[nmax][nmax],n,m,A,B; bool pd(int r,int l,int x){ int pre=0,ans=0,tp=0; rep(i,1,m) if((tp+=a[r][i]-a[l][i])>=x) pre=i,++ans,tp=0; return ans>=B; } bool check(int x){ int pre=0,ans=0; rep(i,1,n) if(pd(i,pre,x)) pre=i,++ans; return ans>=A; } int main(){ freopen("browine.in","r",stdin);freopen("browine.out","w",stdout); n=read(),m=read(),A=read(),B=read();int sm=0; rep(i,1,n) rep(j,1,m) a[i][j]=read(),sm+=a[i][j]; rep(j,1,m) rep(i,1,n) a[i][j]+=a[i-1][j]; int l=0,r=sm,ans=0,mid; while(l<=r){ mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; } /* 5 4 4 2 1 2 2 1 3 1 1 1 2 0 1 3 1 1 1 1 1 1 1 1 */
T3:給出一個500*500的矩陣,要求在同一條直線上取n個點,點的間距>=d。求有多少中方案?it
=>maya肯定兩個端點後這根本不能沒法肯定有多少種方案啊。。。io
正解
枚舉一個點(x,y),先算出(0,0)——>(x,y)這條直線上放N個點,(0,0)處必定放第一個點,(x,y)處必定放最後一個點的方案數,把最後一個點平移(其餘N-1個點跟着總體平移)到以(x,y)爲左上角,(w+1,h+1)爲右下角的矩形中的任何一個格點又是不重複的新的方案。
第一步的方案能夠這樣計算:
設g=gcd(x,y),則(0,0)——>(x,y)的線段上共有g+1個相鄰的距離相同的格點,把這些點從1到g+1編號。設比i點編號大的點中離i最近且距離不小於d的點是i+k,咱們要在這g-1個點(開頭結尾已定)中取n-2個點,知足編號
Xi-Xi-1>=k。此問題等價於
1+k(n-1)<=X2+k(n-2)<=……<=Xn-1+k<=g+1的解的方案數
上面這個問題又等價於
1+k(n-1)+1<=X2+k(n-2)+1<X3+k(n-3)+2<……
<Xn-1+k+(n-2)<=g+1+n-2 的解的方案數
這樣方案數就顯然了,首先開頭結尾都定了,咱們要在[1+k(n-1)+1,g+1+n-2]這g-(k-1)(n-1)-1個數中選出n-2個數,方案數就是原問題的方案數。
時間複雜度O(WH)
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<cmath> using namespace std; #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 clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=505; const int inf=0x7f7f7f7f; const int mod=1e9; int c[nmax][nmax],g[nmax][nmax]; void M(int &a){ if(a>=mod) a-=mod; } int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } void init(){ c[1][0]=1;c[1][1]=1; rep(i,0,500) c[i][0]=1; rep(i,2,500) rep(j,1,i) M(c[i][j]=c[i-1][j]+c[i-1][j-1]); rep(i,1,500) rep(j,1,500) g[i][j]=gcd(i,j); rep(i,1,500) g[i][0]=i,g[0][i]=i;g[0][0]=0; } int cal(int n,int m,int A,int D){ if(A==1) return (n+1)*(m+1); int ans=0,k; rep(i,0,n) rep(j,0,m){ k=(int)((double)D*(g[i][j])/sqrt((double)i*i+j*j)+0.999999); if(g[i][j]-1<A-2||g[i][j]-(k-1)*(A-1)-1<0) continue; M(ans+=1ll*(!i||!j?1:2)*c[g[i][j]-(k-1)*(A-1)-1][A-2]*(n-i+1)%mod*(m-j+1)%mod); } return ans; } int main(){ freopen("backyard.in","r",stdin);freopen("backyard.out","w",stdout); int T=read();init(); rep(_T,1,T){ int A=read(),n=read(),m=read(),D=read(); printf("%d\n",cal(n,m,A,D)); } fclose(stdin);fclose(stdout); return 0; } /* 6 2 4 4 1 13 36 48 5 5 5 5 1 50 49 49 1 6 5 5 2 10 55 75 5 */