zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第二场)

    A:

    这是一道逗鹅题

    队友一上来猜结论 猜对了

    但是wa了

    然后就扔了这题了

    最后我暴力发现队友的结论没错

    然后鹅发现没累乘

    D:

    找团好像没什么快的方法
    只能是暴力
    这个题虽然团有很多很多个
    但是我们只找前k小的就行
    现在的问题在于我们不能按照从小到大依次访问到每个团
    第一个方法是用优先队列
    我们一开始把单个的点扔进去
    每次弹出来一个权值最小的团
    我们虽然不能保证队列里的前k个就是当前的前k小
    但是我们能保证现在队首的是当前最小的
    因为后面在队列里的状态一定比他大
    还没访问的到状态是由队列里的转移过去的 会更大
    所以每次弹出队首一定是正确的
    然后对于队首的状态 他能到达的状态拿到队列里
    这样子 只需要k次弹出就结束了
    每次弹出然后拓展->O(logn+n*X)
    X这里暴力的话是n,就是循环,会tle
    然后用int128或者bitset优化一下就好了

    第二个方法是二分
    回到前面的问题
    我们不能依次从小到大遍历所有的团
    但是如果我们知道一个lim
    我们现在要找权值<=lim的团们
    这样我们就可以暴力的搜索
    如果拓展到一个合法的团 那就继续
    这样的操作会使得k--
    如果扩展到一个不合法的 就停止
    这样只会浪费一次 不会在非法的道路上走得很远
    而这个lim又有单调性 就可以二分
    O(log MAX_lim * k * X)
    这个X是每次找到一个新的最大团时间
    可以用int128优化

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #define maxn 110
    #define tpc __int128
    #define ll long long
    using namespace std;
    ll n,k,w[maxn];
    tpc G[maxn];
    struct node{
        ll big,val;
        tpc S;
        bool operator < (const node &A )const{
            return A.val<val;
        }
    };
    priority_queue<node>q;
    char s[maxn][maxn];
    int main(){
        scanf("%lld%lld",&n,&k);
        k--;node now,tmp;
        for(ll i=1;i<=n;i++)
            scanf("%lld",&w[i]);
        for(ll i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        for(ll i=1;i<=n;i++){
            for(ll j=1;j<=n;j++)
                if(s[i][j]=='1')G[i]+=tpc(1)<<j;
            now.val=w[i];now.S=tpc(1)<<i;
            now.big=i;q.push(now);
        }
        now.val=0;
        for(ll i=1;i<=k;i++){
            if(q.empty()){
                now.val=-1;break;
            }
            now=q.top();q.pop();
            for(ll v=now.big+1;v<=n;v++){
                if((G[v]&now.S)==now.S){
                    tmp.big=v;tmp.val=now.val+w[v];
                    tmp.S=now.S|(tpc(1)<<v);q.push(tmp);
                }
            }
        }
        printf("%lld
    ",now.val);
        return 0;
    }
    View Code
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #define tpc int
    #define maxn 110
    #define ll long long
    using namespace std;
    int n,k,cnt;
    tpc G[maxn],S;
    ll ans,l,r;
    struct node{
        int w,o;
    }a[maxn];
    char s[maxn][maxn];
    int cmp(const node &A,const node &B){
        return A.w<B.w;
    }
    void Dfs(int now,ll val,ll lim){
        int id=a[now].o;
        if(now==n+1||cnt>=k)return;
        if(val+a[now].w>lim)return;
        if((G[id]&S)==S){
            cnt++;S|=tpc(1)<<id;
            Dfs(now+1,val+a[now].w,lim);
            S^=tpc(1)<<id;
        }
        Dfs(now+1,val,lim);
    } 
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i].w);a[i].o=i;r+=a[i].w;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                if(s[i][j]=='1')G[i]+=tpc(1)<<j;
        }
        if(k<=1){
            printf("0
    ");return 0;
        }
        k--;ans=-1;
        while(l<=r){
            ll mid=(l+r)/2;
            cnt=0;S=0;Dfs(1,0,mid);
            if(cnt>=k){
                ans=mid;r=mid-1;
            }
            else l=mid+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    /*
        3 6
        3 2 1
        011
        101
        110
        
        
        5 22
        1 2 3 4 5
        01111
        10111
        11011
        11101
        11110
        
        5 22
        5 4 3 2 1
        01111
        10111
        11011
        11101
        11110
    */
    View Code

    E:

    好奇妙的做法

    线段树维护l行的x到r行的y的方案数,两个区间合并就是矩阵乘法

    啊不要把m写成n啊,要不T的怀疑人生

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define maxn 50010
    #define lc k<<1
    #define rc k<<1|1
    #define mid (l+r)/2
    #define mod 1000000007
    #define ll long long
    using namespace std;
    int n,m,Q,g[maxn][11],s[maxn*4][11][11];
    char c[11];
    void Build(int k,int l,int r){
        if(l==r){
            for(int i=1;i<=m;i++)
                for(int j=1;j<=m;j++)
                    s[k][i][j]=0;
            for(int i=1;i<=m;i++){
                for(int j=i;j>=1;j--)
                    if(g[l][j]==0)s[k][i][j]=1;
                    else break;
            }
            for(int i=1;i<=m;i++){
                for(int j=i;j<=m;j++)
                    if(g[l][j]==0)s[k][i][j]=1;
                    else break;
            }
            return;
        }
        Build(lc,l,mid);Build(rc,mid+1,r);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                s[k][i][j]=0;
        for(int i=1;i<=m;i++)
            for(int t=1;t<=m;t++){
                if(s[lc][i][t]==0)continue;
                for(int j=1;j<=m;j++)
                    s[k][i][j]=(s[k][i][j]+1ll*s[lc][i][t]*s[rc][t][j])%mod;
            }
    }
    void Insert(int k,int l,int r,int x){
        if(l==r){
            for(int i=1;i<=m;i++)
                for(int j=1;j<=m;j++)
                    s[k][i][j]=0;
            for(int i=1;i<=m;i++){
                for(int j=i;j>=1;j--)
                    if(g[l][j]==0)s[k][i][j]=1;
                    else break;
            }
            for(int i=1;i<=m;i++){
                for(int j=i;j<=m;j++)
                    if(g[l][j]==0)s[k][i][j]=1;
                    else break;
            }
            return;
        }
        if(x<=mid)Insert(lc,l,mid,x);
        else Insert(rc,mid+1,r,x);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                s[k][i][j]=0;
        for(int i=1;i<=m;i++)
            for(int t=1;t<=m;t++){
                if(s[lc][i][t]==0)continue;
                for(int j=1;j<=m;j++)
                    s[k][i][j]=(s[k][i][j]+1ll*s[lc][i][t]*s[rc][t][j])%mod;
            }
    }
    int main(){
        scanf("%d%d%d",&n,&m,&Q);
        for(int i=1;i<=n;i++){
            scanf("%s",c+1);
            for(int j=1;j<=m;j++)
                g[i][j]=c[j]-'0';
        }
        Build(1,1,n);int x,y,z;
        while(Q--){
            scanf("%d%d%d",&x,&y,&z);
            if(x==1){
                g[y][z]^=1;Insert(1,1,n,y);
            }
            else printf("%d
    ",s[1][y][z]);
        }
        return 0;
    }
    /*
    2 2 10
    00
    00
    2 1 2
    1 1 2
    2 1 2
    2 1 2
    1 1 2
    2 1 2
    2 1 2
    1 1 2
    2 1 2
    2 1 2
    */
    View Code

    F:

    暴力+最优化剪枝

    ans=所有对之前的val和-队伍内部之间互相打架的val

    后面这个val是递增的,就可以用最优化剪枝

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #define maxn 30
    #define ll long long
    using namespace std;
    int n,g[maxn][maxn],A[maxn],B[maxn];
    ll ans,sum;
    void Dfs(int now,ll s,int a,int b){
        ll res;
        if(now==2*n+1){
            if(ans<sum-s){
                ans=sum-s;//printf("ans : %d
    ",ans);
                //for(int i=1;i<=n*2;i++)printf("%d ",S[i]);printf("
    ");
            }
            return;
        }
        if(a<b){
            res=0;
            for(int i=1;i<=a;i++)
                res+=g[now][A[i]];
            if(sum-s-res>ans&&a<n){
                A[a+1]=now;Dfs(now+1,s+res,a+1,b);A[a+1]=0;
            }
            res=0;
            for(int i=1;i<=b;i++)
                res+=g[now][B[i]];
            if(sum-s-res>ans&&b<n){
                B[b+1]=now;Dfs(now+1,s+res,a,b+1);B[b+1]=0;
            }   
        }
        else {
            res=0;
            for(int i=1;i<=b;i++)
                res+=g[now][B[i]];
            if(sum-s-res>ans&&b<n){
                B[b+1]=now;Dfs(now+1,s+res,a,b+1);B[b+1]=0;
            }   
            res=0;
            for(int i=1;i<=a;i++)
                res+=g[now][A[i]];
            if(sum-s-res>ans&&a<n){
                A[a+1]=now;Dfs(now+1,s+res,a+1,b);A[a+1]=0;
            }
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n*2;i++)
            for(int j=1;j<=n*2;j++){
                scanf("%d",&g[i][j]);sum+=g[i][j];
            }
        sum/=2;Dfs(1,0,0,0);printf("%lld
    ",ans);
        return 0;
    }
    /*
    2
    0 1 1000000000 1000000000
    1 0 1000000000 1000000000
    1000000000 1000000000 0 1
    1000000000 1000000000 1 0 
    */
    View Code

    H:

    枚举删除最大1矩阵的那个边

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1010
    using namespace std;
    int n,m,h[maxn][maxn],l[maxn][maxn],r[maxn][maxn],ans,x1,y1,x2,y2;
    char g[maxn][maxn],t[maxn];
    int Solve(int falg){
        memset(h,0,sizeof(h));
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        int res=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                l[i][j]=r[i][j]=j;
                if(g[i][j]=='0')continue;
                else h[i][j]=h[i-1][j]+1;
            }
    //  printf("h:
    ");
    //  for(int i=1;i<=n;i++){
    //      for(int j=1;j<=m;j++)
    //          printf("%d ",h[i][j]);
    //      printf("
    ");
    //  }
        for(int i=1;i<=n;i++){
            for(int j=2;j<=m;j++){
                if(g[i][j]=='0')continue;
                while(h[i][l[i][j]-1]>=h[i][j])
                    l[i][j]=l[i][l[i][j]-1];
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=m-1;j>=1;j--){
                if(g[i][j]=='0')continue;
                while(h[i][r[i][j]+1]>=h[i][j])
                    r[i][j]=r[i][r[i][j]+1];
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(res<h[i][j]*(r[i][j]-l[i][j]+1)){
                    res=h[i][j]*(r[i][j]-l[i][j]+1);
                    if(falg){
                        x1=i-h[i][j]+1;y1=l[i][j];x2=i;y2=r[i][j];
                    }
                }
            }
        return res;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%s",g[i]+1);
        Solve(1);
        for(int i=y1;i<=y2;i++){
            t[i]=g[x1][i];g[x1][i]='0';
        }
        ans=max(ans,Solve(0));
        for(int i=y1;i<=y2;i++){
            g[x1][i]=t[i];
        }
         
        for(int i=y1;i<=y2;i++){
            t[i]=g[x2][i];g[x2][i]='0';
        }
        ans=max(ans,Solve(0));
        for(int i=y1;i<=y2;i++){
            g[x2][i]=t[i];
        }
         
        for(int i=x1;i<=x2;i++){
            t[i]=g[i][y1];g[i][y1]='0';
        }
        ans=max(ans,Solve(0));
        for(int i=x1;i<=x2;i++){
            g[i][y1]=t[i];
        }
         
        for(int i=x1;i<=x2;i++){
            t[i]=g[i][y2];g[i][y2]='0';
        }
        ans=max(ans,Solve(0));
        for(int i=x1;i<=x2;i++){
            g[i][y2]=t[i];
        }
         
        printf("%d
    ",ans);
        //printf("%d %d %d %d
    ",x1,y1,x2,y2);
        return 0;
    }
    /*
    5 6
    001010
    000110
    010111
    010111
    000110
     
    4 5
    11011
    01010
    10110
    00111
     
    4 9
    001110011
    001110011
    001110011
    000000011
     
     
    */
    View Code

     G:

    蓝书上的板子

    求出所有的多边形面积

    #include<bits/stdc++.h> 
    #define db double
    #define Vector Point
    using namespace std;
    struct Point{
        db x,y;
        Point(db X=0,db Y=0){x=X;y=Y;}
    };
    Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
    Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
    Vector operator * (Vector A,db p){return Vector(A.x*p,A.y*p);}
    Vector operator / (Vector A,db p){return Vector(A.x/p,A.y/p);}
    bool operator < (const Point &a,const Point &b){
        return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    const db eps=1e-10;
    int dcmp(db x){
        if(fabs(x)<eps)return 0;
        else return x<0?-1:1;
    }
    bool operator ==(const Point &a,const Point &b){
        return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
    }
    db Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;}//A B 点积
    db Length(Vector A){return sqrt(Dot(A,A));}//向量长度
    db Angle(Vector A,Vector B){return acos(Dot(A,B)/Length(A)/Length(B));}//A B 夹角
    db Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//A B 叉积
    db Area2(Point A,Point B,Point C){return Cross(B-A,C-A);}//A B 构成的平行四边形面积2倍
    Vector Rotate(Vector A,db rad){//A逆时针旋转rad
        return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
    }
    Vector Normal(Vector A){//返回A的单位法向量
        return Vector(-A.y/Length(A),A.x/Length(A));
    }
    //点和直线
    Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){//返回直线P+tv Q+tw的交点
        Vector u=P-Q;
        db t=Cross(w,u)/Cross(v,w);
        return P+v*t;
    }
    db DistanceToLine(Point P,Point A,Point B){//P到直线AB的距离
        Vector v1=B-A,v2=P-A;
        return fabs(Cross(v1,v2)/Length(v1));
    }
    db DistanceToSegment(Point P,Point A,Point B){//P到线段AB的距离
        if(A==B)return Length(P-A);
        Vector v1=B-A,v2=P-A,v3=P-B;
        if(dcmp(Dot(v1,v2))<0)return Length(v2);
        else if(dcmp(Dot(v1,v3))>0)return Length(v3);
        else return fabs(Cross(v1,v2))/Length(v1);
    }
    Point GetLineProjection(Point P,Point A,Point B){//P在直线AB上的投影
        Vector v=B-A;
        return A+v*(Dot(v,P-A)/Dot(v,v));
    }
    //bool isSL(Point p1,Point p2,Point q1,Point q2){//判断直线p1p2和线段q1q2有无交点(不严格)
    //     return dcmp(Cross(p2-p1,q1-p1)*Cross(p2-p1,q2-p1))!=1;
    //}
    //bool isSL_s(Point p1,Point p2,Point q1,Point q2){//判断直线p1p2和线段q1q2有无交点(严格)
    //     return dcmp(Cross(p2-p1,q1-p1)*Cross(p2-p1,q2-p1))==-1;
    //}
    int isLL(Point k1,Point k2,Point k3,Point k4){// 求直线 k1,k2 和 k3,k4 的交点
        return dcmp(Cross(k3-k1,k4-k1)-Cross(k3-k2,k4-k2))!=0;
    }
    Point getLL(Point k1,Point k2,Point k3,Point k4){
        db w1=Cross(k1-k3,k4-k3),w2=Cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2);
    }
    bool intersect(db l1,db r1,db l2,db r2){
        if(dcmp(l1-r1)==1)swap(l1,r1);if(dcmp(l2-r2)==1)swap(l2,r2);
        return !(dcmp(r1-l2)==-1||dcmp(r2-l1)==-1);
    }
    bool isSS(Point p1,Point p2,Point q1,Point q2){
        return intersect(p1.x,p2.x,q1.x,q2.x)&&intersect(p1.y,p2.y,q1.y,q2.y)&&
        dcmp(Cross(p2-p1,q1-p1)*Cross(p2-p1,q2-p1))!=1&&
        dcmp(Cross(q2-q1,p1-q1)*Cross(q2-q1,p2-q1))!=1;
    }
    bool isSS_s(Point p1,Point p2,Point q1,Point q2){
        return dcmp(Cross(p2-p1,q1-p1)*Cross(p2-p1,q2-p1))==-1
        &&dcmp(Cross(q2-q1,p1-q1)*Cross(q2-q1,p2-q1))==-1;
    }
    db Area(vector<Point> A){ // 多边形用 vector<point> 表示 , 逆时针  求面积 
        db ans=0;
        for (int i=0;i<A.size();i++) ans+=Cross(A[i],A[(i+1)%A.size()]);
        return ans/2;
    }
    //----------------PSLG-------------------------
    typedef vector<Point> Polygon;
    struct Edge{
        int from,to;
        db ang;
        Edge(int f,int t,double a):from(f),to(t),ang(a){}
    };
    const int maxn=1e6+10;    
    struct PSLG{
        int n,m,face_cnt;//face_cnt 面数
        db x[maxn],y[maxn];
        vector<Edge>edges;//储存边
        vector<int>G[maxn];//指向边
        int vis[maxn*2];  // 每条边是否已经访问过
        int left[maxn*2]; // 左面的编号
        int prev[maxn*2]; // 相同起点的上一条边(即顺时针旋转碰到的下一条边)的编号
        vector<Polygon> faces;//faces 储存面
        double area[maxn]; // 每个polygon的面积
        void init(int n){
            this->n = n;
            for(int i = 0; i < n; i++)
                G[i].clear();
            edges.clear();
            faces.clear();
        }
        //from->to的极角
        double getAngle(int from, int to){
            return atan2(y[to]-y[from], x[to]-x[from]);
        }
        void AddEdge(int from, int to){
            edges.push_back((Edge){from, to, getAngle(from, to)});
            edges.push_back((Edge){to, from, getAngle(to, from)});
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
        // 找出faces并计算面积
        void Build(){
            for(int u = 0; u < n; u++){
                // 给从u出发的各条边按极角排序
                int d = G[u].size();
                for(int i = 0; i < d; i++)
                    for(int j = i+1; j < d; j++)
                        if(edges[G[u][i]].ang > edges[G[u][j]].ang)
                            swap(G[u][i], G[u][j]);
     
                for(int i = 0; i < d; i++)
                    prev[G[u][(i+1)%d]] = G[u][i];
            }
            memset(vis, 0, sizeof(vis));
            face_cnt = 0;
            for(int u = 0; u < n; u++)
                for(int i = 0; i < G[u].size(); i++){
                    int e = G[u][i];
                    if(!vis[e]){// 逆时针找圈
                        face_cnt++;
                        Polygon poly;
                        for(;;){
                            vis[e] = 1;
                            left[e] = face_cnt;
                            int from = edges[e].from;
                            poly.push_back(Point(x[from], y[from]));
                            e = prev[e^1];
                            if(e == G[u][i])
                                break;
                            assert(vis[e] == 0);
                        }
                        faces.push_back(poly);
                    }
                }
     
            for(int i = 0; i < faces.size(); i++){
                area[i] = Area(faces[i]);
            }
        }
    };
    //---------------------
    PSLG pslg;
    int n,m,Q;
    Point p[1010][2],a[1010*1010];
    vector<int>v[1010];
    int cmp2(int x,int y){
        return a[x]<a[y];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            p[i][0]=Point(x1,y1);p[i][1]=Point(x2,y2);
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(isLL(p[i][0],p[i][1],p[j][0],p[j][1])){
                    a[m++]=getLL(p[i][0],p[i][1],p[j][0],p[j][1]);
                    v[i].push_back(m-1);v[j].push_back(m-1);
                }
            }
            sort(v[i].begin(),v[i].end(),cmp2);
        }
        pslg.init(m);
        for(int i=0;i<m;i++){
            pslg.x[i]=a[i].x;pslg.y[i]=a[i].y;
        }
        for(int i=1;i<=n;i++)
            if(v[i].size()>=2)
                for(int j=0;j<v[i].size()-1;j++)
                    pslg.AddEdge(v[i][j],v[i][j+1]);
        pslg.Build();
        sort(pslg.area,pslg.area+pslg.face_cnt);
        //for(int i=0;i<pslg.face_cnt;i++)
        //    printf("%.6f
    ",pslg.area[i]);
        printf("%d %.6f %.6f
    ",pslg.face_cnt-1,pslg.area[pslg.face_cnt-1],pslg.area[1]);
        scanf("%d",&Q);int k;
        while(Q--){
            scanf("%d",&k);
            if(k<pslg.face_cnt)printf("%.6f
    ",pslg.area[pslg.face_cnt-k]);
            else printf("Invalid question
    ");
        }
        return 0;
            
    }
    View Code
  • 相关阅读:
    第三个失踪人员,查找在日本王军的朋友
    web.xmlf多ilter在执行顺序
    HDU 1885 Key Task 国家压缩+搜索
    POJ--2923--Relocation--如压力DP
    唯物论、辩证法和认识论
    唯物辩证法的“三大规律”和“五大范畴”-联系与发展
    分析法
    方法论
    哲学的基本问题是什么
    事物分析是一切问题解决的基础和起点
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/11220837.html
Copyright © 2011-2022 走看看