• 叉姐的魔法训练(第一课)---- 初级魔法练习


    一 集合操作

    POJ 2443 Set Operation

    有1000个集合每个集合有10000个元素,给出每个集合所有的元素和Q组询问,问元素x和y是否属于同一个集合。

    手抽写了个集合类出来,效率低了。其实用元素开数组,压缩所属的集合效率更高。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn=1111;
    typedef unsigned int uint;
    const int Size=30;
    class SetOperation{
    private:
        uint st[400];
        int getIdx(int num){
            return num/Size;
        }
        int getLft(int num){
            return num%Size;
        }
    public:
        SetOperation(){
            init();
        }
        void init(){
            memset(st,0,sizeof(st));
        }
        void addVal(int num){
            st[getIdx(num)]|=(1<<getLft(num));
        }
        void delVal(int num){
            st[getIdx(num)]&=~(1<<getLft(num));
        }
        void chgVal(int num){
            st[getIdx(num)]^=(1<<getLft(num));
        }
        bool inSet(int num){
            return st[getIdx(num)]&(1<<getLft(num));
        }
    }a[maxn];
    int main()
    {
        int n,m;
        while (~scanf("%d",&n)){
            for (int i=1;i<=n;i++){
                a[i].init();
                scanf("%d",&m);
                while (m--){
                    int num;
                    scanf("%d",&num);
                    a[i].addVal(num);
                }
            }
            scanf("%d",&m);
            while(m--){
                int x,y;
                bool flag=false;
                scanf("%d%d",&x,&y);
                for (int i=1;i<=n;i++){
                    if (a[i].inSet(x)&&a[i].inSet(y)){
                        flag=true;
                        break;
                    }
                }
                if (flag) printf("Yes
    ");
                else printf("No
    ");
            }
        }
        return 0;
    }
    

    ---------------------------------

    二 公式推导

    POJ 3244 Difference between Triplets


    //数学好题
    //定义两个三元组I(xi,yi,zi)和J(xj,yj,zj),(可以看做是空间中的点)
    //他们的距离为D(I,J)=max{xi-xj,yi-yj,zi-zj}-min{xi-xj,yi-yj,zi-zj},
    //给定n个三元组(n<=200000),求任意两个三元组的差的和
    //抽化出来的模型是 max(a,b,c)-min(a,b,c),这个东西吧他放在数轴上 a,b,c
    //我们要求最大和最小的差就是这三个点构成的线段的距离,那么我们这里再变通下 是不是端点到中间那个点的距离
    //其实画出这个图的时候,就可以看到这个距离为(|a-b|+|b-c|+|c-a|)/2,这样我们并不需要关心中间的那个
    //对应到题目中的原型,就是(|(xi-xj)-(yi-yj)|+|(yi-yj)-(zi-zj)|+|(zi-zj)-(xi-xj)|)/2;
    //对应到同一个点上就是(|(xi-yi)-(xj-yj)|+|(yi-zi)-(yj-zj)|+|(zi-xi)-(zj-xj)|)/2;
    //设a=(xi-yi),b=(yi-zi),c=(zi-xi),原问题等价为(|ai-aj|+|bi-bj|+|ci-cj|)/2;
    //然后三个可以完全分开完全独立的计算,并不影响其他两元,这里要加个优化,就是按从小到大排序出来
    //我们只需要算出每个位置上,他贡献了多少次加法,贡献了多少次减法即可
    //举个例子,目前把a的部分排序了,对于第i个,他前面的比它小,所以在和i点比较时i点贡献了i次加,对后面的n-i个点
    //向他们贡献了n-i次减法

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=411111;
    typedef long long LL;
    LL a[maxn],b[maxn],c[maxn];
    int n;
    
    int main()
    {
        while (~scanf("%d",&n)){
            if (n==0) break;
            for (int i=0;i<n;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                a[i]=x-y;
                b[i]=y-z;
                c[i]=z-x;
            }
            sort(a,a+n);
            sort(b,b+n);
            sort(c,c+n);
            LL ans=0;
            for (int i=0;i<n;i++){
                ans+=(a[i]+b[i]+c[i])*(2*i-n+1);
            }
            printf("%I64d
    ",ans/2);
        }
        return 0;
    }
    

    ---------------------------------

    三 嵌套二分

    POJ 3685 Matrix

    打表后可以发现矩阵存在单调的性质。

    F(i)=i^2+100000*i+j^2-100000*j+i*j 对i求导

    F'(i)=2*i+100000+j>0 恒成立,所以每一列都是单调递增的。

    要求出矩阵中第K大的数。

    首先二分矩阵中的数X,判断它是不是比K个以上的数大。

    然后枚举每一列,对于每一列,二分求出比X小的数的个数。

    累加得到矩阵中比X小的数的个数sum。若sum>=K则X比K个以上的数大。

    最后得到比矩阵中K个以上的数大的数中最小的数ans,则ans-1即为答案。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef __int64 LL;
    const LL INFF=1LL<<50;
    int n;
    LL m;
    LL f(LL i,LL j){
        return i*i+100000*i+j*j-100000*j+i*j;
    }
    bool can(LL x){
        int i;
        LL sum,l,r,res,mid;
        sum=0;
        for (i=1;i<=n;i++){
            l=1,r=n;
            res=n+1;
            while (l<=r){
                mid=(l+r)>>1;
                if (f(mid,i)>=x){
                    res=mid;
                    r=mid-1;
                }
                else{
                    l=mid+1;
                }
            }
            sum+=res-1;
        }
        return sum>=m;
    }
    
    int main()
    {
        int T;
        LL l,r,ans,mid;
        scanf("%d",&T);
        while (T--){
            scanf("%d%I64d",&n,&m);
            l=-INFF,r=INFF;
            ans=0;
            while (l<=r){
                mid=(l+r)>>1;
                if (can(mid)){
                    ans=mid;
                    r=mid-1;
                }
                else{
                    l=mid+1;
                }
            }
            printf("%I64d
    ",ans-1);
        }
        return 0;
    }
    


    ---------------------------------


  • 相关阅读:
    利用VS的预生成事件获取SVN版本作为项目内部版本号
    静态构造函数到底执行了多少次?
    C#之自定义的implicit和explicit转换
    FineUI之使用SQL脚本从数据库表中生成相应的输入控件
    文件操作
    PHP中文件类型 文件属性 路径以及 文件相关的函数
    MySqli 中预处理类 stmt
    MySql 事务处理
    MySqli 执行多条SQL语句
    PHP与MySqli
  • 原文地址:https://www.cnblogs.com/cyendra/p/3681637.html
Copyright © 2020-2023  润新知