• 20190725-20190726


    异或约数和

    题意简述

    求 $f_1space xorspace f_2…space xorspace f_n$ , $f_i$ 表示 $i$ 的所有约数的异或和。

    $nleq 10^{14}$ 。

    $solution:$

    考虑 $xor$ 有结合律与交换律,所以考虑优化给定式子。

    对于 $1-n$ 有 $x$ 这种约数的有 $[dfrac{n}{x}]$ ,直接查约数个数是否为奇数,时间复杂度 $O(n)$。

    而对于 $[dfrac{n}{x}]$ ,当 $xleq sqrt{n}$ 时 $[dfrac{n}{x}]$ 个不相同。

    而当 $x>sqrt{n}$ 时 $[dfrac{n}{x}]$ 只有 $sqrt{n}$ 个取值范围,所以直接暴力维护一下 $[dfrac{n}{x}]$ 即可。

    时间复杂度 $O(sqrt{n})$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    int n,ans;
    inline int Qx(int ps){
        if(!ps) return 0;
        if(ps%4==0) return ps;
        if(ps%4==1) return 1;
        if(ps%4==2) return ps+1;
        if(ps%4==3) return 0;
    }
    inline int Xor(int l,int r){
        return Qx(r)^Qx(l-1);
    }
    int ps;
    signed main(){
        freopen("Xor.in","r",stdin);
        freopen("Xor.out","w",stdout);
        n=read();
        ps=1;
        while(ps<=n){
            int l=ps,r=n/((int)(n/ps)),g=n/ps;
            if(g%2==1) ans^=Xor(l,r);
            ps=r+1;
        }printf("%lld
    ",ans);return 0;
    }
    View Code

    OR三元组

    题意简述

    $q$ 次询问,每次询问满足 $a_i|a_j|a_k=x,i<j<k$ 的三元组 $(i,j,k)$ 的个数。

    $n,qleq10^6,1leq a_i,xleq 255$ 。

    $solution:$

    可以现在 $O(255 imes n)$ 时间内处理出 $f_{i,j}$ 表示前 $i$ 个数中有 $f_{i,j}$ 个数满足 $orspace x=x$ 。

    考虑容斥,$Ans=sum (1space orspace -1)dbinom{i}{3}space(ispace or xspace =x)$ ,而正负 $1$ 直接判断二进制上含 $1$ 的个数差是奇还是偶。

    正确性证明,考虑维恩图,$dbinom{x}{3}$ 表示随机散点的个数,而最后要求的是散到最小的那块个数,因为是 $ispace orspace x=x$,所以最后散到的就是 $x$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=100001;
    int dig[11],n,q,a[MAXN],f[MAXN][256];
    int Q(int g){
        if(g<3) return 0;
        return (g*(g-1)*(g-2))/6;
    }
    int Qdig(int x){
        int Ans=0;
        while(x){
            Ans+=(x&1);
            x/=2;
        }return Ans;
        
    }
    signed main(){
        freopen("Or.in","r",stdin);
        freopen("Or.out","w",stdout);
        n=read(),q=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++){
            for(int j=0;j<=255;j++) if((a[i]&j)==a[i]) f[i][j]++;
        }
        for(int i=1;i<=n;i++)
            for(int j=0;j<=255;j++) f[i][j]+=f[i-1][j];
        for(int i=1;i<=q;i++){
            int l=read(),r=read(),x=read(),ans=0;
            for(int j=0;j<=x;j++){
                if((x|j)==x){
                    int dig=Qdig(x)-Qdig(j);
                    ans+=(dig%2?-1:1)*Q(f[r][j]-f[l-1][j]);
                }
            }printf("%lld
    ",ans);
        }
    }/*
    3 1
    1 1 1
    1 3 1
    
    */
    View Code

    香农游戏

    题意简述

    $T$ 组询问,每次给定 $n$ 个点 $m$ 条边的图,问是否可以存在两组不相交的边集,可以是每个图均联通。

    $T,nleq 10,mleq 100$ 。

    $solution:$

    考虑搜索,若存在图 $G_1,G_2$ 满足条件。

    那么对于现在要搜索的边 $u,v$ ,若在 $G_1$ 中可以减少连通块,那么就选,否则不选。$G_2$ 同理,发现这样就过了。

    因为边集搜索最高对于 $G$ 有 $10$ 条,所以最后的时间复杂度近似于 $O(2^{20} imes w)$ , $w$ 为一个比较小的常数。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=11;
    int n;
    struct Union{
        int f[MAXN],val,sta[MAXN];
        void init(){val=n;for(int i=1;i<=n;i++) f[i]=i;}
        int find(int x){
            if(f[x]==x) return x;
            return find(f[x]);
        }
        void merge(int x,int y){
            int t1=find(x),t2=find(y);
            f[t2]=t1;
            sta[++sta[0]]=t2;
            val--;
        }
        void back(){
            f[sta[sta[0]]]=sta[sta[0]];
            sta[0]--;
            val++;
        }
        void debug(){
            for(int i=1;i<=n;i++) printf("%d ",f[i]);
            printf("
    ");return;
        }
    }G1,G2;
    int T,m;
    struct node{
        int u,v;
    }x[MAXN*MAXN];
    bool flag;
    void dfs(int ps){
        if(flag) return;
        if(G1.val==1&&G2.val==1){flag=1;return;}
        if(ps==m+1) return;
        bool F=1;
        if(G1.find(x[ps].u)!=G1.find(x[ps].v)){
            F=0;
            G1.merge(x[ps].u,x[ps].v);
            dfs(ps+1);
            G1.back();
        }
        if(G2.find(x[ps].u)!=G2.find(x[ps].v)){
            F=0;
            G2.merge(x[ps].u,x[ps].v);
            dfs(ps+1);
            G2.back();
        }
        if(F) dfs(ps+1);
        return;
    }
    void solve(){
        flag=0;
        n=read(),m=read();G1.init(),G2.init();
        for(int i=1;i<=m;i++) x[i].u=read(),x[i].v=read();
        dfs(1);
        if(flag) printf("Possible
    ");
        else printf("Impossible
    ");
        return;
    }
    int main(){
        freopen("Game.in","r",stdin);
        freopen("Game.out","w",stdout);
        T=read();
        while(T--) solve();
    }
    View Code

    致富之路

    题意简述

    有 $m$ 个可供选择的左下角 , $n$ 个可供选择的右上角,问最大矩形面积。

    $n,mleq 10^5$ 。

    $solution:$

    考虑对于左下角的决策点,若 $x$ 相同时肯定 $y$ 最小的是最优的,而当 $x_i<x_j$ 时, $y_i>y_j$ 是更优的。

    右上角决策点也如此,若 $x$ 相同时 $y$ 最大是最优的,而最后我们想看到的是 $x_i<x_j,y_i>y_j$ 的支持删除的,直接单调栈即可。

    现在已经可以求出比较好的决策点,考虑右上角 $(x_1,y_1),(x_2,y_2),(x_1<x_2,y_1>y_2)$ 

    设对于 $(x_1,y_1)$ 的最优左下决策点为 $(x,y)$ ,则对于 $(x_2,y_2)$ 的决策点 $(xx,yy)$ 一定 $xleq xx$ ,可以画图或者推式子得到。

    所以满足决策单调性,直接分治即可,时间复杂度 $O(nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<stack>
    #include<climits>
    #define LL long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=500001;
    int n,m,N,M;
    struct Fac{
        int p,d;
    }f[MAXN],F[MAXN];
    bool cmp1(Fac x1,Fac x2){
        if(x1.p==x2.p) return x1.d<x2.d;
        return x1.p<x2.p;
    }
    struct Com{
        int q,e;
    }g[MAXN],G[MAXN];
    bool cmp2(Com x1,Com x2){
        if(x1.q==x2.q) return x1.e>x2.e;
        return x1.q<x2.q;
    }
    int Mx,My,k[MAXN];
    LL Ans[MAXN];
    stack<int> sta;
    inline void solve(int l,int r,int L,int R){
        if(l>r) return;
        if(L<=0) L=1;
        int mid=l+r>>1,ps=-1;
        for(register int i=L;i<=R;++i){
            if(G[mid].q>=F[i].p&&G[mid].e>=F[i].d){
                LL calc=(LL)(G[mid].q-F[i].p)*(LL)(G[mid].e-F[i].d);
                if(calc>=Ans[mid]){Ans[mid]=calc,ps=i;}
            }
        }
        solve(l,mid-1,L,ps),solve(mid+1,r,ps,R);return;
    }
    signed main(){
        freopen("Rich.in","r",stdin);
        freopen("Rich.out","w",stdout);
        m=read(),n=read();
        for(int i=1;i<=m;i++) f[i].p=read(),f[i].d=read();
        for(int i=1;i<=n;i++) g[i].q=read(),g[i].e=read();
        sort(f+1,f+m+1,cmp1);
        int l=1;
        for(register int i=2;i<=m;++i){
            if(f[i].p==f[i-1].p) continue;
            F[++M]=f[l];
            l=i;
        }
        F[++M]=f[l];
        for(register int i=1;i<=M;i++) f[i]=F[i];
        m=M;
        M=0;F[++M]=f[1];
        for(register int i=2;i<=m;i++){
            if(F[M].d<=f[i].d) continue;
            F[++M]=f[i];
        }
        sort(g+1,g+n+1,cmp2);
        l=0;
        int Minn=INT_MAX;
        for(register int i=1;i<=n;++i){
            while(F[l+1].p<=g[i].q&&l<M) Minn=min(Minn,F[l+1].d),l++;
            if(Minn>g[i].e&&Minn!=LLONG_MAX) continue;
            G[++N]=g[i];
        }
        n=N;
        for(register int i=1;i<=N;++i) g[i]=G[i];
        l=1;N=0;
        for(register int i=2;i<=n;++i){
            if(g[i].q==g[i-1].q) continue;
            G[++N]=g[l];
            l=i;
        }
        G[++N]=g[l];
        n=N;
        for(register int i=1;i<=N;++i) g[i]=G[i];
        for(register int i=1;i<=n;++i){
            while(!sta.empty()){
                int xx=sta.top();
                if(g[xx].e<=g[i].e) sta.pop();
                else break;
            }
            sta.push(i);
        }
        while(!sta.empty()) k[++k[0]]=sta.top(),sta.pop();
        N=k[0];
        for(register int i=1;i<=N;i++) G[i]=g[k[N-i+1]];
        solve(1,N,1,M);
        LL Maxn=0ll;
        for(register int i=1;i<=N;i++) Maxn=max(Maxn,Ans[i]);
        printf("%lld
    ",Maxn);return 0;
    }
    View Code

    菌落

    题意简述

    共 $T$ 组询问。

    有 $n$ 个菌落,每个菌落都有颜色与质量两种属性,最后通过操作将其化为 $1$ 个,问最小代价。

    $nleq 10,Tleq 10$ 。

    $solution:$

    因为 $nleq 10$,考虑状压 $dp$ 或者搜索。

    状压 $dp$ 可以将 $n$ 个数的并查集祖先记录下来,发现总状态数最多为 $10!$ ,直接转移即可。

    时间复杂度 $O(能过)$ 。

    搜索直接暴力贡献最小的几个,因为在绝大多数情况下,贪心与最优策略是一样的,所以就过了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<vector>
    #include<climits>
    #include<cmath>
    #define int long long
    #define LL long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=11;
    struct node{
        int val,col;
    }g[MAXN];
    int T,n;
    LL pw[MAXN],fac[MAXN];
    int Get(int g[]){
        int ans=0;
        for(int i=2;i<=n;i++) ans+=(g[i]-1)*fac[i-1];
        return ans;
    }
    int* Get1(int *EE,int Ans){
        EE[0]=0;
        int Fac=fac[n-1];
        for(int i=n-1;i>=1;--i){
            EE[i+1]=(Ans/Fac)+1;
            Ans%=Fac;
            Fac/=i;
        }
        EE[1]=1;return EE;
    }
    int s[MAXN],tot;
    LL f[36287800];
    vector<int> ve,V;
    char str[MAXN];
    int E[MAXN],S[MAXN],ans0[MAXN],ans1[MAXN];
    inline LL W(int s[]){
        LL sum=0;
        for(register int i=1;i<=n;++i){
            if(!g[i].col) ans0[s[i]]+=g[i].val;
            else ans1[s[i]]+=g[i].val;
        }
        for(register int i=1;i<=n;++i){
            if(s[i]==i) {
                sum+=(LL)abs(ans1[i]-ans0[i])*(LL)abs(ans1[i]-ans0[i]);
                ans1[i]=ans0[i]=0;
            }
        }
        return sum;
    }
    LL Minn,P,Num,GG,H;
    int cnt;
    bool MAP[36287800];
    int bug[MAXN];
    inline void solve(){
        n=read();Minn=LLONG_MAX;
        for(register int i=1;i<=n;++i){
            int val=read();scanf("%s",str+1);
            g[i].val=val;
            if(str[1]=='7') g[i].col=0;
            else g[i].col=1;
        }
        tot=0;
        memset(f,127/3,sizeof(f));
        for(register int i=1;i<=n;++i) s[i]=i;
        Num=Get(s);
        f[Num]=0;f[Num]=0;
        ve.push_back(Num);
        for(register int i=1;i<=n-1;++i){
            int siz=ve.size();
            for(register int j=0;j<siz;++j){
                P=ve[j];
                Get1(s,P);
                E[0]=0;
                for(register int k=1;k<=n;++k)
                    if(s[k]==k) E[++E[0]]=k;
                for(register int k1=1;k1<=E[0];++k1){
                    for(register int k2=k1+1;k2<=E[0];++k2){
                        for(register int k=1;k<=n;++k){
                            cnt++;
                            if(s[k]==E[k2]) S[k]=E[k1];
                            else S[k]=s[k];
                        }    
                        GG=Get(S);
                        if(MAP[GG]==0){MAP[GG]=1;V.push_back(GG);}
                        H=GG;
                        f[H]=min(f[H],f[P]+W(S));
                        if(i==n-1) Minn=min(Minn,f[H]);
                    }
                }
            }
            ve.clear();
            siz=V.size();
            for(register int j=0;j<siz;++j) ve.push_back(V[j]);
            V.clear();
        }
        memset(MAP,0,sizeof(MAP));
        printf("%lld
    ",Minn);return;
    }
    signed main(){
        freopen("germ.in","r",stdin);
        freopen("germ.out","w",stdout);
        T=read();fac[0]=1ll;
        for(int i=1;i<=10;i++) fac[i]=fac[i-1]*i;
        while(T--) solve();
        return 0;
    }
    View Code

    石头

    题意简述

    $T$ 组询问。

    每次求环形最长非严格上升子序列长度,保证数据随机。

    $nleq 10^4,Tleq 10$

    $solution:$

    对于数据随机必定答案不大,考虑 $dp$ 。

    设 $f_{i,j}$ 表示以 $i$ 为结尾,$LIS$ 长度为 $j$ 时的最右左端点。

    $f_{i,j}=max{f_{k,j-1}}space(k<i,a_kleq a_i)$ ,直接数据结构优化即可。

    因为 $j$ 不会很大所以时间复杂度为 $O(答案 imes nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=20001;
    int n,a[MAXN],T,f[MAXN][2];
    struct Bit{
        int maxn[MAXN];
        void clear(){memset(maxn,-127/3,sizeof(maxn));return;}
        int lowbit(int x){return x&-x;}
        int Query(int x){
            int Maxn=INT_MIN;
            for(int i=x;i;i-=lowbit(i)) Maxn=max(Maxn,maxn[i]);
            return Maxn;
        }
        void modify(int x,int w){
            for(int i=x;i<=n;i+=lowbit(i)) maxn[i]=max(maxn[i],w);
            return;
        }
    }bit;
    void solve(){
        n=read();
        for(register int i=1;i<=n;++i) a[i+n]=a[i]=read();
        for(register int i=1;i<=2*n;++i) f[i][0]=i;
        int cur=0;
        for(register int k=2;;++k){
            bit.clear();
            bool flag=0;cur^=1;
            for(int i=1;i<=2*n;i++){
                f[i][cur]=bit.Query(a[i]),bit.modify(a[i],f[i][cur^1]);
                if(i-f[i][cur]+1<=n) flag=1;
            }if(!flag){printf("%d
    ",k-1);return;}
        }
    }
    int main(){
        freopen("stone.in","r",stdin);
        freopen("stone.out","w",stdout);
        T=read();
        while(T--) solve();
    }
    View Code

    翻转项链

    题意简述

    一个长度为 $n$ 的序列,你可以翻转一段区间后求环状最大连续子段和,不能非空,求最大值。

    $nleq 10^5$ 。

    $solution:$

    考虑若翻转区间和最大连续子段和无交集则翻转无用,所以必定有交。

    若两端全有交可以等价于无交,所以只有一段有交时有用的。

    所以问题变为了求环状最大两段子段和,直接分类讨论 $dp$ 即可。

    时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<climits>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200011;
    int n,Maxn,a[MAXN],Maxn1[MAXN],Maxn2[MAXN],sum,Minn1[MAXN],Minn2[MAXN];
    int cnt;
    signed main(){
        freopen("reverse.in","r",stdin);
        freopen("reverse.out","w",stdout);
    //    freopen("10.in","r",stdin);
        n=read();
        Maxn=-LLONG_MAX;
        for(int i=1;i<=n;i++){
            a[i]=read(),sum+=a[i];
            if(a[i]>=0) cnt++;
        }
        if(!cnt){
            sort(a+1,a+n+1);
            printf("%lld
    ",a[n]);
            return 0;
        }
        if(cnt==1){
            sort(a+1,a+n+1);
            printf("%lld
    ",a[n]);
            return 0;
        }
        memset(Maxn1,-127/3,sizeof(Maxn1)),memset(Maxn2,-127/3,sizeof(Maxn2));
        memset(Minn1,127/3,sizeof(Minn1)),memset(Minn2,127/3,sizeof(Minn2));
        for(int i=1;i<=n;i++) Maxn1[i]=max(Maxn1[i-1]+a[i],a[i]),Minn1[i]=min(Minn1[i-1]+a[i],a[i]);
        for(int i=1;i<=n;i++) Maxn1[i]=max(Maxn1[i-1],Maxn1[i]),Minn1[i]=min(Minn1[i-1],Minn1[i]);
        for(int i=n;i>=1;i--) Maxn2[i]=max(Maxn2[i+1]+a[i],a[i]),Minn2[i]=min(Minn2[i+1]+a[i],a[i]);
        for(int i=n;i>=1;i--) Maxn2[i]=max(Maxn2[i+1],Maxn2[i]),Minn2[i]=min(Minn2[i+1],Minn2[i]);
        for(int i=1;i<n;i++){
            Maxn=max(Maxn,Maxn1[i]+Maxn2[i+1]),Maxn=max(Maxn,sum-Minn1[i]-Minn2[i+1]);
        }
        printf("%lld
    ",Maxn);return 0;
    }/*
    3
    -1 1 -1
    */
    View Code
  • 相关阅读:
    cuda npp库旋转图片
    Xml序列化 详解
    jsonp简介
    在centos7下安装.net core
    安装vs2017后造成无法打开xproj项目无法打开
    SqlServer 语法
    js自定义事件
    HttpWebResponse 解压gzip、deflate压缩
    centos7 安装.net core的方法
    帮助类-从tfs获取数据
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11252567.html
Copyright © 2020-2023  润新知