1. 程式人生 > 其它 >3.16(生日快樂!)

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

原題