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

原题

posted @ 2022-03-16 22:30  Authentic_k  阅读(37)  评论(0编辑  收藏  举报