zoukankan      html  css  js  c++  java
  • [日常训练]常州集训day8

    T1

    Description

    给定一个长度为$n$的正整数序列$a$。可以将序列分成若干段,定义第$i$段的权值$x_i$为这一段中所有数的最大值,特殊地,$x_0=0$。求$sum_{i=1}^{m}|x_i-x_{i-1}|$的最小值以及划分方案数,$sum_{i=1}^{m}(x_i-x_{i-1})^2$ 的最小值以及划分方案数,其中$m$为划分的段数。

    Input

    第一行一个整数$n$。第二行$n$个正整数$a_1-a_n$。

    Output

    按顺序输出四个非负整数表示答案,其中两个方案数均对$10^9+7$取模。

    Sample Input

    4
    10 30 20 30

    Sample Output

    30

    6

    500

    3

    HINT

    $n;leq;10^5,1;leq;a_i;leq;10^9$.

    Solution

    从后往前单调栈维护一个不上升序列,记为序列$s$。

    记$s$的长度为$l$,$s[l+1]=0$。将$s$在$a$的位置记为$d$。

    显然,对于一个序列$a$,$sum_{i=1}^{m}|x_i-x_{i-1}|$的最小值为序列中最大的数。

    在$s_i$与$s_{i+1}$之间,定一个断点有$(d_i-d_{i+1})$种方案,不定断点,有$1$种方案。

    所以总方案数为$prod_{i=1}^{m-1}(d_{i}-d_{i+1}+1)$。

    易证$sum_{i=1}^{m}(x_{i}-x_{i-1})^2$的最小值为$sum_{i=1}^{l}(s_{i}-s_{i+1})^2$。

    显然,s中的每一种值至少需要出现一次,所以对于每种值的情况进行考虑。

    在$[d_{i-1},d_i)$这段区间内定一个断点,有$(d_i-d_{i-1})$种方案,不定断点,有$1$种方案。

    由于每个值都必须出现一次,所以不能出现都不定断点的情况。

    记所有不同的值为$b$,则总方案数为$prod_{i=1}^{|b|}(prod_{s[j]=b[i]}(d_{j-1}-d_{j}+1)-1)$

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 1000005
    #define M 1000000007ll
    using namespace std;
    typedef long long ll;
    ll ans,tot=1,sum;
    int a[N],s[N],x[N],t,n;
    inline int read(){
        int ret=0;char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)){
            ret=ret*10+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline ll sqr(ll k){
        return k*k;
    }
    inline void init(){
        n=read();
        for(int i=1;i<=n;++i)
            a[i]=read();
        for(int i=n;i;--i){
            while(t&&a[i]>s[t]) --t;
            s[++t]=a[i];x[t]=i;
        }
        s[t+1]=0;
        for(int i=1;i<t;++i)
            tot=tot*(ll)(x[i]-x[i+1]+1)%M;
        printf("%d
    %lld
    ",s[1],tot);
        for(int i=1;i<=t;++i)
            ans+=sqr((ll)(s[i]-s[i+1]));
        tot=1;
        for(int i=t,j;i;i=j){
            sum=1;
            for(j=i-1;j&&s[j]==s[i];--j);
            for(int k=i;k>j&&k>1;--k)
                sum=sum*(x[k-1]-x[k]+1)%M;
            if(j) --sum;
            tot=tot*(sum)%M;
        }
        printf("%lld
    %lld
    ",ans,tot);
    }
    int main(){
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    T2

    Description

    给定一个质数$p$,构造出一个模$p$意义下的$n$次同余方程,使得该方程在$[0,p)$中的解尽可能少。

    Input

    一行两个整数$n,p$。

    Output

    依次输出$x^n,x^{n-1},…,x^0$前的系数。

    Sample Input

    1 97

    Sample Output

    1 0

    HINT

    $n;leq;100,n<p<10^5,p$为质数。

    Solution

    高次同余方程的概念:$f(x)=0(mod;m)$($f(x)$为次数大于$1$的整式)

    显然$n=1$时,显然所有方程都有$1$个解,任意构造方程即可;

    $n>1$时,设$f(x)=x^n+(p-1)x$。则$f(0)=f(1)$,所以一定存在一个数$y$使得$f(x) ot=y$。

    答案即为$x^n+(p-1)x+(p-t)$即可。

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 100005 
    using namespace std;
    typedef long long ll;
    ll n,p;
    bool b[N];
    inline ll read(){
        ll ret=0;char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)){
            ret=ret*10+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline void init(){
        scanf("%lld%lld",&n,&p);
        if(n==1){
            printf("1 0
    ");return;
        }
        for(ll i=2,k;i<p;++i){
            k=i;
            for(ll j=1;j<n;++j)
                k=k*i%p;
            k=(k+(p-1)*i)%p;
            b[k]=true;
        }
        printf("1 ");
        for(ll i=2;i<n;++i)
            printf("0 ");
        printf("%lld ",p-1);
        for(ll i=1;i<p;++i)
            if(!b[i]){
                printf("%lld
    ",p-i);break;
            }
    }
    int main(){
        freopen("equation.in","r",stdin);
        freopen("equation.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    T3

    Description

    给定一个序列$A$,选择$i,j$,记糟糕指数为$A_i|A_{i+1}|A_{i+2}|…|A_j$,其中|为二进制或运算。

    求有多少组$(i,j)$使得糟糕指数小于$M$。

    Input

    第一行两个正整数$N,M$。
    第二行为$N$个正整数$A_1,A_2,…,A_n$。

    Output

    一行一个整数表示选择方案数。

    Sample Input

    4 6
    1 3 5 1

    Sample Output

    2

    HINT

    $1;leq;N;leq;10^5,0;leq;M;leq;2^{30},1;leq;A_i;leq;2^{30}$

    Solution

    除非有人和我一样因为迷之断句看不懂题目,不然肯定会觉得是一道水题。

    把每个数转成二进制,尺取法即可。

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define M 32
    #define N 1000005
    using namespace std;
    typedef long long ll;
    ll ans;
    int s[N][M],n,m,t;
    inline bool chk(int l,int r){
        int ret=0;
        for(int i=1,k=1;i<M;++i,k<<=1)
            if(s[r][i]-s[l][i]) ret+=k;
        return ret<=m;
    }
    inline void init(){
        scanf("%d%d",&n,&m);
        for(int i=1,k;i<=n;++i){
            scanf("%d",&k);
            for(int j=1;j<M;++j,k>>=1){
                s[i][j]=s[i-1][j];
                if(k&1) ++s[i][j];
            }
        }
        for(int i=1;i<=n;++i){
            t=max(t,i);
            while(t<n&&chk(i-1,t+1)) ++t;
            ans+=(ll)(t-i);
        }
        printf("%lld
    ",ans);
    }
    int main(){
        freopen("evolve.in","r",stdin);
        freopen("evolve.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/AireenYe/p/5810588.html
Copyright © 2011-2022 走看看