3.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,int t) { 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
原题
__EOF__

本文链接:https://www.cnblogs.com/Eternal-Battle/p/16014867.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现