Codeforces Round FF(Div. 2)


layout: post
title: Codeforces Round FF(Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- 线段树
---

传送门

A - DZY Loves Hash (签到)

题意

给你一堆数,让你mod一个值,然后问你第一个重复的值是再第几次输入,没有重复就输出-1

思路

签到

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int a[maxn];
int ans=0;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int p,n;
    cin>>p>>n;
    for(int i=1;i<=n;i++){
        int k;
        cin>>k;
        k%=p;
        if(a[k]&&!ans){
            ans++;
            a[k]++;
            cout<<i<<endl;
        }
        a[k]++;
    }
    if(!ans)cout<<-1<<endl;
    return 0;
}

B - DZY Loves Strings (结论)

题意

给你一个字符串,你可以插入K个字符,每个字符都有一个权值W

img

使得f(s)最大

思路

做过的一题

因为字符个数没有限制 所以直接无脑选最大的就行,然后就是考虑放在哪

如果把字符放前面那么原字符串的某些W值比较小的就会被推到后面使得答案变小

所以直接无脑放最后就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
ll a[maxn];
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    string s;
    cin>>s;
    int k;cin>>k;
    ll mx=0;
    ll ans=0;
    for(int i=0;i<26;i++){
        cin>>a[i];
        mx=max(mx,a[i]);
    }
    int len=s.size();
    for(int i=0;i<len;i++)
        ans+=(i+1LL)*a[s[i]-'a'];
    for(int i=1;i<=k;i++){
        ans+=(len+i*1LL)*mx;
    }
    cout<<ans;
    return 0;
}

C - DZY Loves Sequences (DP)

题意

给你一个数组,你可以改变一个位置的值,让你找到一个最长的严格递增的字串

输出字串长度

思路

一开始直接DP 从头开始做了设
\[ DP[i][0/1]表示到第I个数是否改变的最大值 并且用num[i][0/1]表示当前最后的值的答案 \]
然后果断wa4

后面发现这样只能保证前面的答案,但是如果后面的答案更优就会导致答案错误

所以我们 直接枚举修改的位置然后判断这个修改之后前后能否连接的答案是多少

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
ll head[maxn];
ll tail[maxn];
ll a[maxn];
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    ll ans=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        head[i]=1;
        if(a[i]>a[i-1])head[i]=head[i-1]+1;
        ans=max(ans,head[i]);
        if(i<n)ans=max(ans,head[i]+1);
    }
    for(int i=n;i>=1;i--){
        tail[i]=1;
        if(a[i]<a[i+1])tail[i]=tail[i+1]+1;
        ans=max(ans,tail[i]);
        if(i>1)ans=max(ans,tail[i]+1);
    }
    for(int i=2;i<n;i++){
        if(a[i-1]<a[i+1]-1)ans=max(head[i-1]+tail[i+1]+1,ans);
    }


    cout<<ans;
    return 0;
}

D - DZY Loves Modification( 优先队列)

题意

给出一个N×M的矩阵,每次可以使得一行或者一列的所有元素减少P

然后答案加上删去P之前的行(列)的值

让你输出必须操作K次之后的最大值

思路

首先行和列直接是有关联的 不好处理

那么我们想想有没有办法分离行列之间的关系

我们发现如果我们删去任意一行 这是每一列的值都会减少P

假设我们删了q次行,那么对于后面的每一次删除列的值都会减少q×P

所以行列之间的关系找到了

假设我们删去了一列那么我们的答案为P+(删去列获得的值)-q×P

然后我们可以发现再固定删去行的次数之后 每次删去列的次数也固定了,

假设删去K次行,那么之后的答案肯定会少去{q×P×(k-q)}

那么我们就只需要使得答案没有删去之前的答案最大就行了,

那么我们直接优先队列乱搞就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
priority_queue<ll>prow,pcol;
ll row[maxn],col[maxn];
ll a[1200][1200];
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n,m,k,p;
    cin>>n>>m>>k>>p;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        ll sum=0;
        for(int j=1;j<=m;j++){
            sum+=a[i][j];
        }
        prow.push(sum);
    }
    for(int i=1;i<=m;i++){
        ll sum=0;
        for(int j=1;j<=n;j++){
            sum+=a[j][i];
        }
        pcol.push(sum);
    }
    for(int i=1;i<=k;i++){
        row[i]=prow.top();
        prow.pop();
        prow.push(row[i]-1LL*m*p);
        row[i]+=row[i-1];
    }
    for(int i=1;i<=k;i++){
        col[i]=pcol.top();
        pcol.pop();
        pcol.push(col[i]-1LL*n*p);
        col[i]+=col[i-1];
    }
    ll ans=-inf;
    for(int i=0;i<=k;i++){
        ans=max(ans,row[i]+col[k-i]-1LL*(1LL*i*(k-i))*p);
    }
    cout<<ans;
    return 0;
}

E - DZY Loves Fibonacci Numbers(线段树+斐波那契数列性质)

题意

给你一个数组,你有两种操作,

1.把一个区间的值依次加上斐波那契数列的(i-start+1)项的值

2.输出一个区间的合

思路

参考

首先讨论斐波那契的性质

现在给出与本题有关的三个性质

1:若a,b满足
\[ a_{n+2}=a_n+a_{n+1},b_{n+2}=b_n+b_{n+1} \]

\[ c_n=a_n+b_n \]
那么
\[ c_1=a_1+b_1,c_2=a_2+b_2,c_{n+2}=c_n+c_{n+1} \]
2:有通项公式
\[ a_n=F_{n-2}a_1+F_{n-1}a_2 \]
3:

有前缀和公示
\[ \sum_{i=1}^n a_i=a_{n+2}-a_2 \]
接下来证明时间

证明1:
\[ c_{n+2}=a_{n+2}+b_{n+2}=(a_n+a_{n+1})+(b_n+b_{n+1})=(a_n+b_n)+(a_{n+1}+b_{n+1})=c_n+c_{n+1} \]
证明2:

1378193-20190228143256304-1840278.png

证明3:
\[ \begin{align} 2\Sigma_{i=1}^n a_i &= (a_1+a_2+...+a_n)+(a_1+a_2+...+a_n) \\ &=a_1+(a_1+a_2)+(a_2+a_3)+...+(a_{n-1}+a_n)+a_n \\ &=a_1+a_n+(a_3+a_4...+a_{n+1}) \\ &=(a_1+a_2+...+a_n)-a_2+a_n+a_{n+1} \\ &=\Sigma_{i=1}^n a_i+a_{n+2}-a_2 \\ \Sigma_{i=1}^n a_i &=a_{n+2}-a_2 \end{align} \]
所以我们可以记录 通过前两项的值就得出一段区间的和

通过性质1,我们知道 前两项的答案 可以叠加;
通过性质2,我们可以O(1)地将前两项的值下放;
通过性质3,我们可以O(1)地更新sum。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+9;
const int maxn=3e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
ll sum[maxn];
ll a[maxn];
ll fib[maxn];
struct SegTree{
    struct node{
        ll f1,f2,sum;
    }my[maxn<<4];
    #define ls (o<<1)
    #define rs (o<<1|1)
    void push_up(int o,int len){
        my[o].f1%=mod;my[o].f2%=mod;
        my[o].sum=my[ls].sum+my[rs].sum+
        ((my[o].f1*fib[len])%mod+(my[o].f2*fib[len+1]%mod)-my[o].f2+mod)%mod;
        my[o].sum%=mod;
    }
    void push_down(int o,int l,int r){
        if(!my[o].f1&&!my[o].f2)return ;
        int mid=(l+r)/2;
        my[ls].f1+=my[o].f1;
        my[rs].f1+=(my[o].f1*fib[mid-l])%mod+(my[o].f2*fib[mid-l+1])%mod;
        my[ls].f2+=my[o].f2;
        my[rs].f2+=(my[o].f1*fib[mid-l+1])%mod+(my[o].f2*fib[mid-l+2])%mod;
        my[o].f1=my[o].f2=0;
        push_up(ls,mid-l+1);
        push_up(rs,r-mid);
    }
    void ins(int o,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            my[o].f1+=fib[l-ql+1];
            my[o].f1%=mod;
            my[o].f2+=fib[l-ql+2];
            my[o].f2%=mod;
            push_up(o,r-l+1);
            return;
        }
        push_down(o,l,r);
        int mid=(l+r)/2;
        if(ql<=mid)ins(ls,l,mid,ql,qr);
        if(qr>mid)ins(rs,mid+1,r,ql,qr);
        push_up(o,r-l+1);
    }
    ll query(int o,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            return my[o].sum;
        }
        push_down(o,l,r);
        int mid=(l+r)/2;
        ll ans=0;
        if(ql<=mid)ans+=query(ls,l,mid,ql,qr);
        if(qr>mid)ans+=query(rs,mid+1,r,ql,qr);
        ans%=mod;
        return ans;
    }
}seg;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n,m;
    cin>>n>>m;
    fib[1]=fib[2]=1;
    for(int i=3;i<=n+3;i++)fib[i]=(fib[i-1]+fib[i-2])%mod;
    for(int i=1;i<=n;i++)cin>>a[i],sum[i]=(sum[i-1]+a[i])%mod;
    while(m--){
        int op,l,r;
        cin>>op>>l>>r;
        if(op==1)seg.ins(1,1,n,l,r);
        else cout<<(seg.query(1,1,n,l,r)+(sum[r]-sum[l-1])%mod+mod)%mod<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/luowentao/p/10450224.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值