zoukankan      html  css  js  c++  java
  • Gym 101964 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)

    传送门

    A.Numbers

     

    B.Broken Watch 

           先考虑最简单的情况,就是a,b,c都相等的情况,这个时候答案显然只会跟n有关系,在n个线段里面选3个的情况就是C(n,3),其中有一部分不合法,这个时候考虑怎样是不合法的,现在设取三条边分别是x,y,z;当x经过y到达z的这个角的角度小于180度的时候,那么这个方案必然是不合法的,这样的话只需要确定x和z就可以确定一族不可行的方案,x和z可以夹1....[n/2](上取整)条边,也就是形成了[n/2](上取整)族答案,每一族的方案数分别是1...[n/2]。于是用总的方案数减去(1+2+3+...+[n/2](上取整))即可。这里的答案是对2^64取模,因此统计答案时要处理一下除法。
            对于a,b,c不相等的情况直接乘上A(3,1)或A(3,3)即可
    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    int main(){
    
        int a,b,c;
        ll n;
        scanf("%d%d%d%llu",&a,&b,&c,&n);
        ll tmp=(n+1)/2;
        tmp-=2;
        ll ans=0;
        //特判除以6的情况
        ll tmp1=n,tmp2=n-1,tmp3=n-2;
        if(tmp1%2==0) tmp1/=2;
        else if((tmp2)%2==0) tmp2/=2;
        if(tmp1%3==0) tmp1/=3;
        else if(tmp2%3==0) tmp2/=3;
        else if(tmp3%3==0) tmp3/=3;
        ans=tmp1*tmp2*tmp3;
        
        ans-=n*(tmp*(tmp+1)/2);
        
        if(a!=b&&b!=c&&c!=a){//全都不相同
            ans*=6;
        }
        else if(a!=b||a!=c||b!=c){//有一个不同
            ans*=3;
        }
        printf("%llu
    ",ans);
        return 0;
    }
    View Code

    C.Tree

      首先,题目中的”使得最大值最小“这句话就非常符合二分的条件了。因此我们考虑对答案(两个黑点的最远的距离)进行二分。

      现在就要考虑如何进行check。

            对于每一个二分值k,我们考虑先用bfs遍历整颗树,然后利用bfs的性质(距离当前点的所有已bfs过且小于等于d的那些点,他们之间两两距离也小于等于k),找出满足距离等于k的对应的一个个点集。之后我们可以用dfs去遍历这些点集,判断点集中的黑点的个数与需要选取的黑点个数m之间的关系即可(如果数量>=n,则右指针左移动;反之左指针右移)。

    #include <bits/stdc++.h>
    #define maxn 105
    using namespace std;
    vector<int>vec[maxn];
    int vis[maxn];//用vis数组去区分点的不同的集合
    int a[maxn];
    queue<int>que;
    int n,m;
    int ans=0;
    int dfs(int now,int fa,int all,int dis){
        int res=a[now];
        if(dis==all) return res;
        for(auto &it:vec[now]){
            if(!vis[it]||it==fa) continue;
            res+=dfs(it,now,all,dis+1);
        }
        return res;
    }
    bool check(int k){//二分的check,本质上为一个bfs
        memset(vis,0,sizeof(vis));
        while(!que.empty()) que.pop();
        que.push(1);
        while(!que.empty()){//bfs选取部分点集
            int now=que.front();
            que.pop();
            vis[now]=1;
            int tmp=dfs(now,0,k,0);//通过dfs获取这个集合的黑点的个数
            if(tmp>=m) return 1;
            for(auto &it:vec[now]){
                if(vis[it]) continue;
                que.push(it);
            }
        }
        return 0;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=0;i<n-1;i++){
            int from,to;
            scanf("%d%d",&from,&to);
            vec[from].push_back(to);
            vec[to].push_back(from);
        }
        int l=0,r=n;
        while(l<r){
            int mid=(l+r)>>1;
            if(check(mid)) r=mid;
            else l=mid+1;
            //cout<<l<<" "<<r<<endl;
        }
        cout<<r<<endl;
    }
    View Code

    D.Space Station


    E.Fishermen

      我们可以先把渔夫的位置排个序,然后遍历所有的鱼,每一条鱼能够被可以被抓都在x轴有一个范围,通过二分,在渔夫中找到最左的和最右的,然后差分一下,最后求个前缀和就可以得出答案

    #include <bits/stdc++.h>
    using namespace std;
    typedef  long long ll;
    const int maxn=2e5+7;
    struct SS{
        int x,y;
    }a[maxn];
    struct S{
        int x,id,idd;
        bool operator <(const S &bb)const {
            return x<bb.x;
        }
    }b[maxn];
    int sum[maxn],ans[maxn];
    int main(){
        //freopen("in.txt","r",stdin);
        int n,m,l;
        scanf("%d %d %d",&n,&m,&l);
        for (int i=1;i<=n;i++)
            scanf("%d %d",&a[i].x,&a[i].y);
        for (int i=1;i<=m;i++) {
            scanf("%d",&b[i].x);
            b[i].id=i;
        }
        sort(b+1,b+m+1);
        for (int i=1;i<=m;i++) b[i].idd=i;
        for (int i=1;i<=n;i++){
            if (a[i].y-l>0) continue;
            S tmp;
            tmp.x=a[i].x-l+a[i].y;
            int xx=lower_bound(b+1,b+m+1,tmp)-b;
            tmp.x=a[i].x+l-a[i].y;
            int yy=upper_bound(b+1,b+m+1,tmp)-b;
            sum[xx]++;
            sum[yy]--;
        }
        for (int i=1;i<=m;i++){
            sum[i]+=sum[i-1];
            ans[b[i].id]=sum[b[i].idd];
        }
        for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    F.Min Max Convert


    G.Matrix Queries


    H.Modern Djinn


    I.Inversion

      首先,我们要把原序列还原,根据逆序对的性质,还原出原序列。接着,根据题意两个对集合的定义,可以知道选出的那个点集是从左到右升序的,且点集中最小的点在序列中左边没有比它更小的点,最大的点在序列中右边没有比它更大的点,所以我们可以进行dp,dp[i]表示以i为点集最后一个点的答案的数量。
      dp转移见代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=107;
    int du[maxn],a[maxn],vis[maxn];
    ll dp[maxn];
    int main(){
       // freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m,x,y;
        cin>>n>>m;
        while (m--){
            cin>>x>>y;
            du[min(x,y)]++;
        }
        for (int i=1;i<=n;i++){//还原序列
            for (int j=1;j<=n;j++) {
                if (!vis[j]) {
                    if (du[i]) du[i]--;
                    else {
                        a[i]=j;
                        vis[j]=1;
                        break;
                    }
                }
            }
        }
     //   for (int i=1;i<=n;i++) cout<<a[i]<<' ';cout<<endl;
        for (int i=1;i<=n;i++){
            ll res=0,mx=0;
            for (int j=i-1;j;j--){
                if (a[j]>a[i]) continue;// 对答案无贡献
                if (a[j]>mx) res+=dp[j],mx=a[j];//所有小于mx的值对应位置的dp值都在之前加入到res中了,不再重复加
            }
            dp[i]=max(1ll,res);// 当i前面无比a[i]小的数时,dp[i]为1,它为第一个点也为最后一个点
        }
        ll ans=0,mx=0;
        for (int i=n;i;i--){
            if (a[i]>mx) ans+=dp[i],mx=a[i];//同上mx的解释
        }
      //  for (int i=1;i<=n;i++) cout<<dp[i]<<' ';cout<<endl;
        cout<<ans<<endl;
        return 0;
    }
    View Code

    J.Rabbit vs Turtle


    K.Points and Rectangles

  • 相关阅读:
    URAL 1736 Chinese Hockey 网络流+建图
    python基础教程_学习笔记14:标准库:一些最爱——re
    吐槽下CSDN编辑器
    让你提前认识软件开发(23):怎样在C语言中运行shell命令?
    GDB十分钟教程
    任务调度开源框架Quartz动态加入、改动和删除定时任务
    AfxMessageBox和MessageBox差别
    Linux Shell脚本入门--awk命令详解
    鲁棒性的获得 —— 测试的架构
    C Tricks(十八)—— 整数绝对值的实现
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/9879980.html
Copyright © 2011-2022 走看看