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\n",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\n");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\n",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

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\n",ans);
            //for(int i=1;i<=n*2;i++)printf("%d ",S[i]);printf("\n");
        }
        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\n",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:\n");
//  for(int i=1;i<=n;i++){
//      for(int j=1;j<=m;j++)
//          printf("%d ",h[i][j]);
//      printf("\n");
//  }
    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\n",ans);
    //printf("%d %d %d %d\n",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

猜你喜欢

转载自www.cnblogs.com/yanlifneg/p/11220837.html
今日推荐