Codeforces Round #FF (Div. 1)简单题解

A .DZY Loves Sequences

pro:给定长度为N的序列,你最多可以改变一个数的值,问最长严格上升子序列长度。 N<1e5.

sol:分几种情况,一种的不改变; 一种是改变,然后接上一个; 一个是改变中间一个,接上两段,而且满足a[mid-1]<a[mid]<a[mid+1]

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn=100010;
int a[maxn],L[maxn],R[maxn];
int main()
{
    int N,ans=0; scanf("%d",&N);
    rep(i,1,N) scanf("%d",&a[i]);
    rep(i,1,N) {
        L[i]=1;
        if(i>1&&a[i]>a[i-1]) L[i]=L[i-1]+1;
    }
    for(int i=N;i>=1;i--){
        R[i]=1;
        if(i<N&&a[i]<a[i+1]) R[i]=R[i+1]+1;
    }
    rep(i,1,N) ans=max(ans,L[i]);
    rep(i,1,N) ans=max(ans,R[i]);
    rep(i,1,N-2) {
        if(a[i]<a[i+2]-1) ans=max(ans,L[i]+R[i+2]+1);
    }
    rep(i,1,N-1) ans=max(ans,L[i]+1);
    rep(i,2,N) ans=max(ans,R[i]+1);
    printf("%d\n",ans);
    return 0;
}

B .DZY Loves Modification

pro:给定N*M有数字的矩阵 ,现在你可以进行K次操作,每次操作,你会选择一行或者一列,把其对应的数字和加到sum里,然后对应的每个数字减少P,问K次操作后最大的sum是多少。 N,M<1e3, K<1e6, p<1e2;

sol:关键在于想到,如果取的行数和列数次数确定了,那么他们相互影响的值是固定的。 然后就可以行列分开考虑了,我们考虑行,我们要取前K大,那么就是单调队列贪心取最大即可搞定。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=1010;
ll N,M,K,P,a[maxn][maxn],X[maxn],Y[maxn],t;
priority_queue<ll>A,B;
ll sumA[maxn*maxn],sumB[maxn*maxn],ans;
int main()
{
    scanf("%lld%lld%lld%lld",&N,&M,&K,&P);
    rep(i,1,N) rep(j,1,M) scanf("%lld",&a[i][j]);
    rep(i,1,N) rep(j,1,M) X[i]=X[i]+a[i][j];
    rep(i,1,N) rep(j,1,M) Y[j]=Y[j]+a[i][j];
    rep(i,1,N) A.push(X[i]);
    rep(i,1,M) B.push(Y[i]);
    rep(i,1,K){
        t=A.top(); A.pop(); sumA[i]=t; A.push(t-M*P);
        t=B.top(); B.pop(); sumB[i]=t; B.push(t-N*P);
    }
    rep(i,1,K) sumA[i]+=sumA[i-1],sumB[i]+=sumB[i-1];
    ans=sumB[K];
    rep(i,1,K){
        ans=max(ans,sumA[i]+sumB[K-i]-1LL*i*(K-i)*P);
    }
    printf("%lld\n",ans);
    return 0;
}

C .DZY Loves Fibonacci Numbers

pro:给定一个大小为N的数组,现在进行Q次操作,1操作为区间加值,假如是区间[L,R],那么a[i]+=F[i-L+1],F是fib数列; 2操作为区间求和; N,Q<3e5;

sol:此题好像有几种方法,官方题解是用逆元blabla,感觉有点取巧。 然后线段树有两种解法。 一种是利用fib数列的性质,fib加fib还是有fib的性质,可以参考:

https://blog.csdn.net/johann_oier/article/details/49070067 。 但是这种方法的tag传递还是容易出错。

另外一种方法是利用fib数列的另外一个性质:Fn+m=Fn+1*Fm+Fn*Fm-1; 所以我们可以可以把相同的部分提出来,不相同的用前缀和操作。

即假如对区间[L,R]操作,对x增加F[x-L+1]=F[x+1]*F[-L]+F[x]*F[-1-L];而F[x+1]和F[x]我们可以预处理出来(代码里是A和B,而F[-L]我们不难倒推出来)

这种方法比较巧妙,这样救和普通lazy操作无异,所以常数很小。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int Mod=1e9+9;
const int maxn=2000010;
int sum[maxn],lazy1[maxn],lazy2[maxn],N;
int A[maxn],B[maxn],F[maxn],pre[maxn],fcy[maxn];
void MOD(int &x){ if(x>=Mod) x-=Mod;}
void pushup(int Now)
{
    sum[Now]=(sum[Now<<1]+sum[Now<<1|1])%Mod;
}
void build(int Now,int L,int R)
{
    MOD(A[Now]=(pre[R+1]-pre[L]+Mod));
    MOD(B[Now]=(pre[R]-pre[L-1]+Mod));
    if(L==R){ scanf("%d",&sum[Now]); return;}
    int Mid=(L+R)>>1;
    build(Now<<1,L,Mid); build(Now<<1|1,Mid+1,R);
    pushup(Now);
}
void pushdown(int Now,int L,int R)
{
    int Mid=(L+R)>>1;
    if(lazy1[Now]){
        MOD(sum[Now<<1]+=1LL*lazy1[Now]*A[Now<<1]%Mod);
        MOD(lazy1[Now<<1]+=lazy1[Now]);
        MOD(sum[Now<<1|1]+=1LL*lazy1[Now]*A[Now<<1|1]%Mod);
        MOD(lazy1[Now<<1|1]+=lazy1[Now]);
        lazy1[Now]=0;
    }
    if(lazy2[Now]){
        MOD(sum[Now<<1]+=1LL*lazy2[Now]*B[Now<<1]%Mod);
        MOD(lazy2[Now<<1]+=lazy2[Now]);
        MOD(sum[Now<<1|1]+=1LL*lazy2[Now]*B[Now<<1|1]%Mod);
        MOD(lazy2[Now<<1|1]+=lazy2[Now]);
        lazy2[Now]=0;
    }
}
void update(int Now,int L,int R,int l,int r)
{
    if(l<=L&&r>=R){
        MOD(sum[Now]+=1LL*fcy[1-l+N]*A[Now]%Mod);
        MOD(sum[Now]+=1LL*fcy[-l+N]*B[Now]%Mod);
        MOD(lazy1[Now]+=fcy[1-l+N]);
        MOD(lazy2[Now]+=fcy[-l+N]);
        return;
    }
    pushdown(Now,L,R); int Mid=(L+R)>>1;
    if(l<=Mid) update(Now<<1,L,Mid,l,r);
    if(r>Mid) update(Now<<1|1,Mid+1,R,l,r);
    pushup(Now);
}
int query(int Now,int L,int R,int l,int r)
{
    if(l<=L&&r>=R) return sum[Now];
    int res=0,Mid=(L+R)>>1; pushdown(Now,L,R);
    if(l<=Mid) (res+=query(Now<<1,L,Mid,l,r))%=Mod;
    if(r>Mid) (res+=query(Now<<1|1,Mid+1,R,l,r))%=Mod;
    pushup(Now); return res;
}
int main()
{
    int M,opt,L,R;
    scanf("%d%d",&N,&M);
    F[1]=1; F[2]=1;
    rep(i,3,N+1) MOD(F[i]=F[i-1]+F[i-2]);
    rep(i,1,N+1) MOD(pre[i]=pre[i-1]+F[i]);
    fcy[N+1]=1; fcy[N]=0; //对应负数的fib
    for(int i=N-1;i>=0;i--) MOD(fcy[i]=fcy[i+2]-fcy[i+1]+Mod);
    build(1,1,N);
    rep(i,1,M){
        scanf("%d%d%d",&opt,&L,&R);
        if(opt==1) update(1,1,N,L,R);
        else printf("%d\n",query(1,1,N,L,R));
    }
    return 0;
}

D .DZY Loves Games

pro:给定N给点,有M条边的连通图,其中一些是黑点,一些是白点。 一开始在1号点,保证1号是白点,N号是黑点。 一开始有K滴血,每次走到一个黑点掉一滴血,每次在一个点会随机走到相邻的点,现在问第让他还有2滴血进入到N号点的概率。

sol:用高斯消元求出黑点之间走到的而不讲过其他黑点的概率,然后矩阵快速幂得到K-2次到N号点的概率。

(不会高斯消元,待补

。。。

原文地址:https://www.cnblogs.com/hua-dong/p/10454185.html

时间: 2024-10-10 04:17:23

Codeforces Round #FF (Div. 1)简单题解的相关文章

Codeforces Round #316 (Div. 2) 简单题解

简单小结:A题先找出每个城市中得票最高的然后再在以上求出的那帮人中出一个得票(一个城市只算一票)中最高的 1 /*********************************** 2 * * 3 * Auther Rhapsody * 4 * E-mail [email protected] * 5 * * 6 ***********************************/ 7 #include <set> 8 #include <map> 9 #include &l

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces Round #FF (Div. 1)-A,B,C

A:DZY Loves Sequences 一开始看错题了..sad. 题目很简单,做法也很简单.DP一下就好了. dp[i][0]:到当前位置,没有任何数改变,得到的长度. dp[i][1]:到当前位置,改变了一个数,得到的长度 不过需要正向求一遍,然后反向求一遍. #include<iostream> #include<stdio.h> #include<algorithm> #include<stdlib.h> #include<string.h

DP Codeforces Round #FF (Div. 1) A. DZY Loves Sequences

题目传送门 /* DP:先用l,r数组记录前缀后缀上升长度,最大值会在三种情况中产生: 1. a[i-1] + 1 < a[i+1],可以改a[i],那么值为l[i-1] + r[i+1] + 1 2. l[i-1] + 1 3. r[i+1] + 1 //修改a[i] */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN =

# Codeforces Round #529(Div.3)个人题解

Codeforces Round #529(Div.3)个人题解 前言: 闲来无事补了前天的cf,想着最近刷题有点点怠惰,就直接一场cf一场cf的刷算了,以后的题解也都会以每场的形式写出来 A. Repeating Cipher 传送门 题意:第一个字母写一次,第二个字母写两次,依次递推,求原字符串是什么 题解:1.2.3.4,非常明显的d=1的等差数列,所以预处理一个等差数列直接取等差数列的每一项即可 代码: #include<bits/stdc++.h> using namespace s

Codeforces Round #531 (Div. 3) ABCDE题解

Codeforces Round #531 (Div. 3) 题目总链接:https://codeforces.com/contest/1102 A. Integer Sequence Dividing 题意: 给一个数n,然后要求你把1,2.....n分为两个集合,使得两个集合里面元素的和的差的绝对值最小. 题解: 分析可以发现,当n%4==0 或者 n%3==0,答案为0:其余答案为1.之后输出一下就好了. 代码如下: #include <bits/stdc++.h> using name

Codeforces Round #540 (Div. 3) 部分题解

Codeforces Round #540 (Div. 3) 题目链接:https://codeforces.com/contest/1118 题目太多啦,解释题意都花很多时间...还有事情要做,就选一些题来写吧. B. Tanya and Candies 题意: 在n个数中任意删去一个,如果这个数被删去后,剩余数的奇数和以及偶数和相等,那么就定义这个数为"好数".现在问这n个数中有多少个“好数”. 题解: 预处理出奇数前缀和.偶数前缀和,删去一个数后所有的奇数位置和 就为前面的奇数和

Codeforces Round #632 (Div. 2) 部分题解

目录 Codeforces Round #632 (Div. 2) A. Little Artem B. Kind Anton C. Eugene and an array D. Challenges in school №41 F. Kate and imperfection Codeforces Round #632 (Div. 2) A. Little Artem 题意:略. 分析:构造这样的图形: BWW...W BWW...W BBB...B #include <bits/stdc++

Codeforces Round #105 (Div. 2) (ABCDE题解)

比赛链接:http://codeforces.com/contest/148 比较简单的一场,最长的一题也才写了30行多一点 A. Insomnia cure time limit per test:2 seconds memory limit per test:256 megabytes ?One dragon. Two dragon. Three dragon?, - the princess was counting. She had trouble falling asleep, and