3.16(生日快樂!)
阿新 • • 發佈:2022-03-16
T1
首先考試的時候就想到了網路流,甚至想到了文理分科。
考試時感覺和文理分科這道題很類似
回憶一下文理分科
大概一樣就是某些選擇組合起來有著多餘的代價
建圖的話,按照最小割來建圖
大概就是把互斥的東西放到兩邊,首先文理分科,學文學理是互斥的
那麼組合出來的意義新加一個節點連到理科上
#include<bits/stdc++.h> #define INF 2147483647 #define MAXN 1000005 using namespace std; int head[MAXN],nxt[MAXN],val[MAXN],to[MAXN],tot=-1; int dis[MAXN],n,m; int GX[5]={0,1,-1,0,0}; int GY[5]={0,0,0,1,-1}; void add(int u,int v,int w) { tot++; to[tot]=v; val[tot]=w; nxt[tot]=head[u]; head[u]=tot; } int id1(int x,int y) { return (x-1)*m+y; } int id2(int x,int y) { return (x-1)*m+y+n*m; } bool bfs(int s,intt) { memset(dis,-1,sizeof(dis)); queue<int>q; q.push(s); dis[s]=0; while(!q.empty()) { int now=q.front(); // cout<<"now1: "<<now<<endl; q.pop(); for(int i=head[now];i!=-1;i=nxt[i]) {int y=to[i]; // cout<<"val1: "<<val[i]<<endl; if(dis[y]==-1&&val[i]) { dis[y]=dis[now]+1; q.push(y); } } } // cout<<"dis: "<<dis[t]<<endl; return dis[t]!=-1; } int dfs(int now,int ed,int flow) { // cout<<"now: "<<now<<" "<<ed<<" "<<flow<<endl; if(now==ed) return flow; int rest=flow; for(int i=head[now];i!=-1&&rest;i=nxt[i]) { int y=to[i]; // cout<<"val: "<<val[i]<<endl; if(dis[y]!=dis[now]+1||(!val[i])) continue; int k=dfs(y,ed,min(val[i],rest)); rest-=k; val[i]-=k; val[i^1]+=k; if(!k) dis[y]=-1; } return flow-rest; } int Dinic(int s,int t) { int res=0; while(bfs(s,t)) { res+=dfs(s,t,INF); } return res; } int Ans,art,sec,Ad,s,t; int main() { // freopen("a.out","w",stdout); cin>>n>>m; s=0,t=n*m*4+1; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { add(id1(i,j),id2(i,j),INF); add(id2(i,j),id1(i,j),0); // cout<<id1(i,j)<<" "<<id2(i,j)<<endl; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&art); Ans+=art; add(s,id1(i,j),art); add(id1(i,j),s,0); // cout<<s<<" "<<id1(i,j)<<endl; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&sec); Ans+=sec; add(id2(i,j),t,sec); add(t,id2(i,j),0); // cout<<id2(i,j)<<" "<<t<<endl; } } int nx,ny,Poi=2*n*m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { ++Poi; scanf("%d",&Ad); Ans+=Ad; add(s,Poi,Ad); add(Poi,s,0); // cout<<s<<" "<<Poi<<endl; add(Poi,id1(i,j),INF); add(id1(i,j),Poi,0); // cout<<Poi<<" "<<id1(i,j)<<endl; for(int k=1;k<=4;k++) { nx=i+GX[k],ny=j+GY[k]; if(nx<=0||ny<=0||nx>n||ny>m) continue; add(Poi,id1(nx,ny),INF); add(id1(nx,ny),Poi,0); // cout<<Poi<<" "<<id1(nx,ny)<<endl; } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { ++Poi; scanf("%d",&Ad); Ans+=Ad; add(Poi,t,Ad); add(t,Poi,0); // cout<<Poi<<" "<<t<<endl; add(id2(i,j),Poi,INF); add(Poi,id2(i,j),0); // cout<<id2(i,j)<<" "<<Poi<<endl; for(int k=1;k<=4;k++) { nx=i+GX[k],ny=j+GY[k]; if(nx<=0||ny<=0||nx>n||ny>m) continue; add(id2(nx,ny),Poi,INF); add(Poi,id2(nx,ny),0); // cout<<id2(nx,ny)<<" "<<Poi<<endl; } } } cout<<Ans-Dinic(s,t); }
才發現自己文理分科沒寫...補上了,瞬間透徹
考試時候會了這個這道題就跟切菜一樣...(儘管我當時不會文理分科 -_-|| )
無非是分為串分為正反(一開始我想的是把串分正反結果發現無法建圖)兩個節點,如果正反串都出現了,那麼貢獻+=2,否則沒有貢獻,我們當然是讓貢獻越少越好,那麼就考慮讓一個串只被分到一邊就好了,大概就是選一邊的話,考慮文理分科的做法,一開始的貢獻全部累計進去,然後如果只選一邊的話就把貢獻減去,不過這個建圖不是最終建圖。
這個和文理分科不太一樣,這個跑出來最大流就是答案
我們要答案最小,那就是最大流(最小割)了
考慮建圖,首先正串向反串連邊流量是2,然後考慮每個行列的限制,一開始先不讓單詞與源匯相連,那麼對於每行列建點,正向單詞連出,反向單詞連入,然後這個建邊的邊權也是INF,我們最後的答案肯定是選最少的邊權使得兩個點斷開,那麼就考慮這樣跑出來的最大流,就是必然每個點都做出了決策,首先肯定每個要求只能一個方向讀,那麼顯然的大部分邊(除了都是迴文串只能選一邊),那麼由於每個都要做決策,那麼對於原圖來說,只要中間一個邊被割掉了,就要增加貢獻,那麼就是求最小貢獻,就是最小割
T2
上午寫出了正解,需要加一點奇技淫巧...而且還卡精度,導致我調了一下午
#include<bits/stdc++.h> //#define double long double #define MAXN 4000005 using namespace std; const double PI=acos(-1),eps=1e-12; struct node { double x,y; node(double x_=0,double y_=0): x(x_),y(y_){} node operator * (node &a) {return (node){x*a.x-y*a.y,x*a.y+y*a.x};} node operator + (node &a) {return (node){x+a.x,y+a.y};} node operator - (node &a) {return (node){x-a.x,y-a.y};} }a[MAXN],A[MAXN],B[MAXN],res[MAXN],Mid[MAXN]; int l=0,len=1,rev[MAXN]; void FFT(node *a, int type) { for(int i = 0; i <= len; ++i) if(i < rev[i]) swap(a[i], a[rev[i]]); for(int mid = 1; mid < len; mid <<= 1) { node Wn(cos(PI / mid), type * sin(PI / mid) ); for(int r = mid << 1, j = 0; j < len; j += r) { node w(1, 0); for(int k = 0; k < mid; ++k, w = w * Wn) { node x = a[j + k], y = w * a[j + mid + k]; a[j + k] = x + y; a[j + k + mid] = x - y; } } } // if(type == -1) {for(int i = 0; i < len; ++i) a[i].x /= ; } } //void FFT(node *A,int type) //{ // for(int i=0;i<=len;i++) // { // if(i<rev[i]) // { // swap(A[i],A[rev[i]]); // } // } // for(int mid=1;mid<len;mid<<=1) // { // node Wh(cos(PI/mid),type*sin(PI/mid)); // for(int r=mid<<1,j=0;j<len;j+=r) // { // node w(1,0); // for(int k=0;k<mid;k++,w=w*Wh) // { // node x=A[j+k]; // node y=w*A[j+k+mid]; // A[j+k]=x+y; // A[j+k+mid]=x-y; // } // } // } //} void mul(node *a, int lena,node *b, int lenb, node *c) { l = 0; for(len = 1; len <= lena + lenb; len <<= 1) l++; for(int i = 0; i < len; ++i) rev[i] = ((rev[i>>1]>>1) | ((i&1) << (l-1))); for(int i = 0; i < len; ++i) A[i] = node{a[i].x, 0}, B[i] = node{b[i].x, 0}; FFT(A, 1); FFT(B, 1); for(int i = 0; i < len; ++i) A[i] = A[i] * B[i]; // cout<<"A = "<<endl; // for(int i = 0; i < bit; ++i) cout<<A[i].x<<" "; cout<<endl; FFT(A, -1); if(true) {for(int i = 0; i < len; ++i) A[i].x /= len; } // cout<<"B = "<<endl; // for(int i = 0; i < bit; ++i) cout<<A[i].x<<" "; cout<<endl; for(int i = 0; i <= lena + lenb; ++i) c[i].x = A[i].x; } //void mul(node *A,int len1,node *B,int len2,int opt) //{ // len=1,l=0; // while(len<(len1+len2)) len<<=1,l++; // for(int i=0;i<=len;i++) // { // rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1)); // } // if(opt==0) // { // FFT(A,1); // for(int i=0;i<len;i++) // { // A[i]=(A[i]*A[i]); // } // FFT(A,-1); // for(int i=0;i<len;i++) // { // A[i].x/=len; // } // return ; // } // FFT(A,1); // FFT(B,1); // for(int i=0;i<len;i++) // { // A[i]=(A[i]*B[i]); // } // FFT(A,-1); // FFT(B,-1); // for(int i=0;i<len;i++) // { // A[i].x/=len; // B[i].x/=len; // } //// return *A; //} void cut(node *A,int &Len,int &ls) { // return ; // cout<<"pre: "<<Len<<endl; while(A[Len].x<eps) Len--; // cout<<"nxt: "<<Len<<endl; int len=0; while(A[len].x<eps) len++,ls++; for(int i=len;i<=Len;i++) { A[i-len]=A[i]; } Len-=(len-1); // cout<<"Len: "<<Len<<endl; } int X,Y,tmp1=0,tmp2=0,RL; void my_pow(node *A,int k) { res[0].x=1; RL=0; int cnt=0; while(k) { if(k&1) { // cout<<"F = "<<endl; mul(res,RL,A,X,res); RL+=X; tmp1+=tmp2; cut(res,RL,tmp1); } cut(A,X,tmp2); mul(A,X,A,X,A); X<<=1; // for(int i = 0; i <= X; ++i) printf("%.6f ", A[i].x); cout<<endl; tmp2*=2; cut(A,X,tmp2); k>>=1; } } int a1,a2; double Sum[MAXN]; void Init() { memset(Sum,0,sizeof(Sum)); memset(Mid,0,sizeof(Mid)); memset(res,0,sizeof(res)); memset(a,0,sizeof(a)); tmp1=tmp2=0; } void sol() { Init(); scanf("%d%d",&X,&Y); for(int i=0;i<X;i++) { a[i].x=1.0/X; } X--; my_pow(a,Y); // cout<<"tmp: "<<tmp<<" "<<RL<<endl; // for(int i=0;i<=X+Y;i++) // { // printf("%.6f ",res[i].x); // } // cout<<endl; // cout<<tmp<<endl; // for(int i = 0; i <= RL; ++i) printf("%.6f ", res[i].x); // cout<<tmp1<<endl; // tmp1=2869; for(int i=0;i<tmp1;i++) { Sum[i]=0; } for(int i=tmp1;i<=MAXN-5;i++) { Sum[i]=Sum[i-1]+res[i-tmp1].x; } // for(int i=RL+1;i<=MAXN-5;i++) // { // Sum[i]=1.0; // } for(int i=1;i<=10;i++) { cin>>a1>>a2; if(a1==0) { printf("%.6f\n",Sum[a2]); } else { // cout<<Sum[a2]<<" "<<Sum[a1-1]<<endl; printf("%.6f\n",Sum[a2]-Sum[a1-1]); } } } int T; int main() { // freopen("a.out","w",stdout); scanf("%d",&T); while(T--) sol(); }
T3