2020牛客多校第八场

比赛链接

  • I Interesting Computer Game
    并查集维护每个点是否在环内。
    题意:
    每次给你n个pair,每个pair有两个数a,b,现在要求每次在a,b中选一个,并且选的那个不能是之前选过的数。
    解法:
    每次输入a,b就在数a,b之间连一条双向边,然后设答案为所有的点都能取到,最后遍历每个团,如果一个团里不含有环,就是n个点(n-1)条边的情况,那必然答案有个点取不到,而有环的团一定有大于等于点数的边数,不用减。
    要注意处理读入时赋予顶点编号的先后关系,如某个pair是3 3。
    还是数组要开2倍,因为每个pair会有两个不同的数。
    初始化时候要注意范围。
**#include <bits/stdc++.h>
using namespace std;
const int maxn=2*(int)1e5+100;
int tc,n,fa[maxn],circle[maxn];
int findRoot(int x){
    if(x==fa[x]) return x;
    else{
        return fa[x]=findRoot(fa[x]);
    }
}
void uniRoot(int a, int b){  //并查集维护团内是否有环
    int aa=findRoot(a);
    int bb=findRoot(b);
    if(aa!=bb){
        fa[bb]=aa;
        circle[aa]|=circle[bb];
    } else circle[aa]=1;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    int kase=1;
    cin>>tc;
    while(tc--){
        cin>>n;
        for(int i=0; i<=200010; ++i){
            fa[i]=i;
            circle[i]=0;
        }
        map<int,int> cnt;
        int tot=0;
        for(int i=0; i<n; ++i){
            int a,b;
            cin>>a>>b;
            int na=cnt[a];
            if(!na){
                cnt[a]=++tot;
                na=tot;
            }
            int nb=cnt[b];
            if(!nb){
                cnt[b]=++tot;
                nb=tot;
            }
            uniRoot(na, nb);
        }
        int ans=tot;
        for(int i=1; i<=tot; ++i){
            if(findRoot(i)==i){
                if(circle[i]==0) --ans;//没有环,有一个点肯定选不到
            }
        }
        cout<<"Case #"<<kase++<<": "<<ans<<'\n';
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}
**
  • K Kabaleo Lite
    题意:
    有n个物品,每个物品都有数量和利润,每个客人来一定要拿走1~n连续个数的物品,现在问你最多能来多少客人,利润是多少。
    解法:
    读题后要明确题目第一优先级是来最多数目的客人,然后才是最大化利润。
    首先最多能来的客人就是第一个利润前缀和为正的那个位置物品的个数。
    然后每次前缀和达到新高值就放在某个vector里,然后从后往前遍历,更新答案就行辣。
    极限情况是1e5*1e5*1e9=1e19超long long,这时候就要用牛客特色的__int128,或者用两个longlong存。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=(ll)1e5+100;
ll tc,n,a[maxn],b[maxn],pre[maxn];
__int128 read(){
    __int128 x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void print(__int128 x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    int kase=1;
    scanf("%lld", &tc);
    while(tc--){
        scanf("%lld", &n);
        for(int i=1; i<=n; ++i) scanf("%lld", &a[i]);
        for(int i=1; i<=n; ++i) scanf("%lld", &b[i]);
        ll maxx=LLONG_MIN;
        vector<ll> p;
        pre[0]=0;
        for(int i=1; i<=n; ++i){
            pre[i]=pre[i-1]+a[i];
            if(pre[i]>maxx){
                maxx=pre[i];
                p.emplace_back(i);
            }
        }
        for(int i=2; i<=n; ++i){
            b[i]=min(b[i], b[i-1]);
        }
        __int128 ans=0;
        __int128 use=0;
        for (int i=int(p.size())-1; i>=0; --i){
            __int128 cnt=b[p[i]]-use;
            __int128 num=pre[p[i]];
            ans+=cnt*num;
            use=b[p[i]];
        }
        printf("Case #%d: %lld ", kase++, b[1]);
        print(ans);
        puts("");
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

  • G Game SET
    模拟,暴力出奇迹
    题意:
    有t组数据,每组数据给你n个串,每个串由4个部分组成,每个部分都可以由不同的东西组成,*表示可以替代任意部分,现在问你存不存在一组三个串答案,使这三个串的每部分要么全都相同,要么全都不相同。
    t<=1000
    n<=256
    解法:
    这道题真的是印证了那句话暴力出奇迹,第一眼看t*n^3怎么可能不T,然而有证明只要遍历30个就一定能找到一组解,官方给的题解我就看了一眼,也就10几页吧(,打扰了。
    学到了,以后遇到过的队伍多的题,没思路就暴力交一发,万一过了呢。
#include <bits/stdc++.h>
using namespace std;
const int maxn=500;
struct node{
    string a[5];
}nd[maxn];
int tc,n;
bool same(string a, string b){
    if(a==b) return true;
    if(a=="*"||b=="*") return true;
    return false;
}
bool diff(string a, string b){
    if(a=="*"||b=="*") return true;
    if(a!=b) return true;
    return false;
}
bool solve(int t1,int t2,int t3){
    for(int i=0; i<4; ++i){
        if(same(nd[t1].a[i], nd[t2].a[i]) && same(nd[t2].a[i], nd[t3].a[i])) continue;
        if(!diff(nd[t1].a[i], nd[t2].a[i]) || !diff(nd[t1].a[i], nd[t3].a[i])
           || !diff(nd[t2].a[i], nd[t3].a[i])) return false;
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif
    int kase=1;
    cin>>tc;
    while(tc--){
        cin>>n;
        bool ok=false;
        string all;
        for(int i=1; i<=n; ++i){
            cin>>all;
            int cnt=0;
            string ta,tb,tc, td;
            for(char c:all){
                if(c=='[') ++cnt;
                else if(c==']') continue;
                else{
                    if(cnt==1) ta+=c;
                    else if(cnt==2) tb+=c;
                    else if(cnt==3) tc+=c;
                    else td+=c;
                }
            }
            nd[i].a[0]=ta;
            nd[i].a[1]=tb;
            nd[i].a[2]=tc;
            nd[i].a[3]=td;
        }
        int ans1,ans2,ans3;
        for(int i=1; i<=n; ++i){
            for(int j=i+1; j<=n; ++j){
                for(int k=j+1; k<=n; ++k){
                    if(solve(i, j, k)){
                        ans1=i;ans2=j;ans3=k;
                        ok=true;
                        break;
                    }
                }
                if(ok) break;
            }
            if(ok) break;
        }
        if(ok) cout<<"Case #"<<kase++<<": "<<ans1<<' '<<ans2<<' '<<ans3<<'\n';
        else cout<<"Case #"<<kase++<<": "<<-1<<'\n';
    }
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值