[雅礼NOIP2018集训 day1]

现在才来填坑,之后还要陆续补其他几天的,可能前几天真的太颓了


T1:

题目大意:给定一个长度为n的序列,m次询问每次询问给出l,r,询问区间l到r的元素在模k意义下的最大值

数据范围当然是你暴力写不过的...

老实说我考场敲了主席树,不幸的是只拿到了暴力的分

考虑正解?我们分块。预处理出每一块在模k意义下的最大值,多余部分暴力计算就好

上面一句话显然是废话,我么怎么预处理出每一块在模任意k意义下的最大值呢?

显然在$[ak,(a+1)k)$这一段值域中,数值最大值一定是最优的,我们可以开个表记录当前块中小于等于当前数字的最大的元素的大小,预处理统计一段的答案时就是取小于等于$(a+1)k-1$的最大值就好了

发现$[ak,(a+1)k)$的区间一共有$klnk$个,其实我也不知道怎么得到的,这样时间复杂度好像就对了,实测卡过去是比较轻松的

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;

const int N=1e5;
const int M=1e2;
int n,m;
int a[N+5],lst[N+5],ans[M][N+5];
inline int read()
{
    char ch=getchar();
    int s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
int main()
{
//    freopen("flower.in","r",stdin);
//    freopen("flower.out","w",stdout);
    int B=1000;
    n=read();m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    int siz=(n-1)/B;
    for (int i=0;i<=siz;i++)
    {
        memset(lst,0,sizeof(lst));
        int l=i*B+1,r=min(n,(i+1)*B);
        for (int j=l;j<=r;j++) lst[a[j]]=a[j];
        for (int j=1;j<=N;j++) lst[j]=max(lst[j],lst[j-1]);
        for (int j=1;j<=N;j++) for (int k=0;k<=N;k+=j) ans[i][j]=max(ans[i][j],lst[min(N,k+j-1)]-k);
    }
    while (m--)
    {
        int l=read(),r=read(),k=read();
        int L=(l-1)/B,R=(r-1)/B,re=0;
        for (int i=L+1;i<R;i++) re=max(re,ans[i][k]);
        for (int i=l;i<=min((L+1)*B,r);i++) re=max(re,a[i]%k);
        for (int i=max(l,R*B+1);i<=r;i++) re=max(re,a[i]%k);
        printf("%d
",re);
    }
    return 0;
}
View Code

T2:

emm这题出题人很坑啊,像笔者这样的蒟蒻在看到条件1的时候就直接按y排序了,出题人的意思是这样不好优化,笔者在考场上好像也许可能大概刚出了时间复杂度正确的前缀和优化,无奈死在了128MB的空间上

正解是按x排序,$dp_{i,0/1}$表示以第i个点为顶端的向左和向右的方案数。注意到当前点的x值是最大的,那么显然只能在前i个点中只能作为折线的第一个点或第二个点

那么有两种转移方法

$dp_{j,1}->dp_{i,0}$  $y_j<y_i$

$dp_{k,1}->dp_{j,1}$ $y_j>y_i,y_k<y_i,x_k>x_j$

以上显然都有$x_i>x_j,x_i>x_k$

发现第二种转移可以前缀和优化一下

#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;

const int N=6e3+15;
const int mod=1e9+7;
int n;
ll dp[N][2];
struct node
{
    ll x,y;
}e[N];
inline ll read()
{
    char ch=getchar();
    ll s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
bool cmp(node a,node b) {return a.x<b.x;}
int main()
{
    //freopen("refract.in", "r", stdin);
    //freopen("refract.out", "w", stdout);
    n=read();
    for (int i=1;i<=n;i++) {e[i].x=read();e[i].y=read();}
    sort(e+1,e+1+n,cmp);
    for (int i=1;i<=n;i++)
    {    
        dp[i][0]=dp[i][1]=1;
        for (int j=i-1;j>=1;j--) 
            if (e[j].y<e[i].y) (dp[i][0]+=dp[j][1])%=mod;
            else (dp[j][1]+=dp[i][0])%=mod;
    }
    ll ans=mod-n;//dp[i][0]和dp[i][1]算重了 
    for (int i=1;i<=n;i++) (ans+=dp[i][0]+dp[i][1])%=mod;
    printf("%lld
",ans);
    return 0;
}
View Code

T3:

待填

原文地址:https://www.cnblogs.com/xxzh/p/9743189.html