zoukankan      html  css  js  c++  java
  • Codeforces 314 and 315

    315 C

    题意

    (n) 个元素,有 (a,d) 两个属性

    (d_i) 的计算公式为

    现在找到第一个满足 (d_ile k) 的元素,将其删除,重新计算其余元素的 (d_i)
    重复进行此操作,直到没有可以删除的元素为止
    依次输出被删除元素的编号
    ((1 ≤ n ≤ 2·10^5))

    Examples

    Input
    5 0
    5 3 4 1 2
    Output
    2
    3
    4
    Input
    10 -10
    5 5 1 7 5 1 2 4 9 2
    Output
    2
    4
    5
    7
    8
    9

    推了很久,终于推出来了
    将公式变形,每次删除掉下标为 (k) 的元素之后,其余元素的 (d_i) 的变化为:

    [d_i+=a_i*(i-1)(i<k) ]

    [d_i+=-sum_{j=k+1}{i-1}a_j+(n-i)*a_i-a_k*(k-1) ]

    用一个sum变量维护 (sum_{j=k+1}{i-1}a_j) 部分,cnt变量维护 ((n-i)*a_i) 部分,add变量维护 (a_k*(k-1)) 部分
    (O(n)) 扫即可

    Code

    #include<bits/stdc++.h>
    #define maxn 200003
    using namespace std;
    long long n,cnt,k,a[maxn],d[maxn],add,sum;
    int main(){
        scanf("%lld%lld",&n,&k);
        sum=0;
        for(int i=1;i<=n;i++){
            scanf("%lld",a+i);
            d[i]=sum-(i-1)*(n-i)*a[i];
            sum+=(i-1)*a[i];
        }
        sum=0;
        for(int i=1;i<=n;i++){
            if(d[i]-sum+cnt*(n-i)*a[i]-add<k){
                printf("%d
    ",i);
                add+=a[i]*(i-1);
                cnt++;
            }
            else{
                sum+=a[i]*cnt;
            }
        }
        return 0;
    }
    

    315 D

    题意

    ([a,b]) 表示周期为 (b) ,每个周期中的字符串为 (a) 的一个字符串
    现在给你两个串 (a,b),两个正整数 (c,d)
    问满足 ([[b,d],p])([a,c]) 的子序列的最大的 (p) 是多少
    ( (1le |a|,|b|le 100,1le c,dle 10^7) )

    Examples

    Input
    10 3
    abab
    bab
    Output
    3

    令字符串下标从一开始
    维护一个 (f) 数组, (f[i]) 表示 (b[i..|b|])(a) 中出现了几次
    再来一个 (nxt) 数组(有一点点类似kmp), (nxt[i]) 表示 (b) 匹配 (a) 匹配完一遍以后指 (b) 的指针指在哪个位置
    最后,for(int i=1;i<=c;i++)ans+=f[pos],pos=nxt[pos];
    然后手膜一遍,发现效率异常高,达到了 (O(n))

    Code

    #include<bits/stdc++.h>
    #define maxn 103
    using namespace std;
    char s[maxn],t[maxn];
    int a,b,n,m,f[maxn],nxt[maxn],ans,pos;
    int main(){
        scanf("%d%d%s%s",&a,&b,s+1,t+1);
        n=strlen(s+1),m=strlen(t+1);
        for(int i=1;i<=m;i++){
            pos=i;
            for(int j=1;j<=n;j++){
                if(t[pos]==s[j])pos++;
                if(pos==m+1)f[i]++,pos=1;
            }
            nxt[i]=pos;
        }
        pos=1;
        for(int i=1;i<=a;i++){
            ans+=f[pos];
            pos=nxt[pos];
        }
        printf("%d
    ",ans/b);
        return 0;
    }
    

    315 E

    题意

    给你一个序列,找出该序列的所有最长非减子序列(不能有重复元素),求所有这些子序列的价值的和。
    一个子序列的价值定义为该序列中所有元素的乘积
    答案膜 (10^9+7)
    ( (1le nle 10^5,1le a_ile 10^6) )

    Examples

    Input
    1
    42
    Output
    42
    Input
    3
    1 2 2
    Output
    13
    Input
    5
    1 2 3 4 5
    Output
    719

    (dp[i]) 表示枚举到第 (i) 个元素的答案
    凑一凑,转移方程就能出来: (dp[i]=sum_{a[j]le a[i];and;j<i}dp[j]*a[j]+a[j])
    等式右边的左侧的前缀和可以用树状数组维护
    但是,不能有重复元素!!!
    注意到 (a_ile 10^6)
    所以我们另设一个数组 (last)(last[a[i]]) 表示上一个与 (a[i]) 相等的元素的 (dp)
    (dp[i]) 减去 (last[a[i]]) 即可
    但是,更新 (last[a[i]]) 时切记不可以直接 (last[a[i]]=dp[i]) !!!

    Code

    #include<bits/stdc++.h>
    #define maxn 100003
    #define mod 1000000007
    using namespace std;
    long long dp[maxn],last[1000003],ans,a[maxn],mx,t[1000003];
    int n;
    void add(int pos,long long k){
        while(pos<=mx){
            t[pos]=(t[pos]+k)%mod;
            pos+=pos&-pos;
        }
    }
    long long query(int pos){
        long long ret=0;
        while(pos){
            ret=(ret+t[pos])%mod;
            pos-=pos&-pos;
        }
        return ret;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%lld",a+i),mx=max(mx,a[i]);
        for(int i=1;i<=n;i++){
            dp[i]=(mod+(query(a[i])*a[i]%mod+a[i])%mod-last[a[i]])%mod;
            last[a[i]]=(query(a[i])*a[i]%mod+a[i])%mod;
            ans=(ans+dp[i])%mod;
            add(a[i],dp[i]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    

    314 D

    题意

    平面上有 (n) 个点,现在有两条直线,互相垂直,与 (x) 轴呈 (45°) 角,定义 (dis(i)) 为点 (i) 到两条直线的曼哈顿距离( (|x_1-x_2|+|y_1-y_2|) )中较小的一个
    移动两条直线使得 (max{dis(i)}) 最小
    ( (1le nle 10^5) )

    Examples

    Input
    4
    0 0
    2 0
    0 2
    2 2
    Output
    0.000000000000000
    Input
    4
    1 0
    0 1
    2 1
    1 2
    Output
    1.000000000000000

    发现点 (i) 到某条直线的曼哈顿距离必定是点 (i) 到这条直线的距离的 (sqrt{2}) 倍。
    所以我们将整个坐标轴旋转 (45°) ,这样,原来坐标为 ((x,y)) 的点变成了 ((x-y,x+y)) ,而且坐标还是整数(long long即可解决)。
    问题转化为求两条分别与x轴、y轴平行的直线
    将点按x坐标排序
    然后我们二分 (max{dis(i)})
    设二分出的值为mid
    用两个指针维护距离至多为2mid的两条平行于y轴的直线
    两条直线中间的点一定是合法的
    问题在于两条直线之外的点
    其实,只要两条直线之外的点y坐标最大值减最小值是小于等于2
    mid的,我们就构造出了一种可行解,return true
    前缀、后缀的最大值、最小值可以先预处理出来

    Code

    #include<bits/stdc++.h>
    #define maxn 100003
    #define INF 100000000000000000ll
    using namespace std;
    struct point{
        long long x,y;
        point(){}
        point(long long _x,long long _y):x(_x),y(_y){}
        bool operator <(const point& p)const{return x==p.x?y<p.y:x<p.x;}
    };
    
    point a[maxn];
    int n;
    long long mx1[maxn],mi1[maxn],mx2[maxn],mi2[maxn];
    bool check(long long M){
        for(int i=1,j=1;i<=n;i++,j=max(i,j)){
            while(j<=n&&a[j].x-a[i].x<=M)j++;j--;
    // printf("i:%d j:%d
    ",i,j);
            if(max(mx2[j+1],mx1[i-1])-min(mi2[j+1],mi1[i-1])<=M)return 1;
        }
        return 0;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            long long x,y;
            scanf("%lld%lld",&x,&y);
            a[i]=point(x-y,x+y);
        }
        sort(a+1,a+n+1);
        mx1[0]=mx2[n+1]=-INF,mi1[0]=mi2[n+1]=INF;
        for(int i=1;i<=n;i++){
            mx1[i]=max(mx1[i-1],a[i].y);
            mi1[i]=min(mi1[i-1],a[i].y);
        }
        for(int i=n;i>=1;i--){
            mx2[i]=max(mx2[i+1],a[i].y);
            mi2[i]=min(mi2[i+1],a[i].y);
        }
        long long l=0,r=4000000000ll,mid,ans=r;
        while(l<=r){
            mid=(l+r)>>1;
            if(check(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%.12lf
    ",ans*0.5);
        return 0;
    }
    
  • 相关阅读:
    利用索引提高SQL Server数据处理的效率
    拆掉思维里的墙摘抄
    QR码和PDF417比较
    保存一个记录到数据库又马上返回ID号
    C#获取当前路径的7种方法
    汉诺塔算法不错,收藏了!
    如何确定Z检验的值(查正态分布表时要注意中间的数字都是面积,最左边一列和最上面一行都是Z值)
    opencv的安装
    SQL事务
    重大财务决策前的思考
  • 原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/10387961.html
Copyright © 2011-2022 走看看