2017.11.09离线赛总结

来源:互联网 发布:怎样属于数组下标越界 编辑:程序博客网 时间:2024/06/16 07:12

kth ——3820

思路:这是一道比较玄学的题目。
首先,此题一定是二分答案,且它的上界应为k,而前缀和直接维护仅只有90。

不难发现每个数的方案数应该与它因子有关,
xy=i,不妨令x<y,那么可以有x[1,sqrt(i)],y[sqrt(i),i]
可以简单地打表出x,y的分布会长成这样:
yi,ij,ij,...2,2,2,...,2,1,1,1,1,1...,1
x1,i/(ij),i/(ij),...,i/2,i/2,...,i/2,i,i,i,...,i

那么就可以“跳区间”似的找第k大的数,因为当我们知道x=num,一定是先知道它的L,那么它的R=pos[i/(num+1)]1

code

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cstdlib>#include<algorithm>#include<vector>using namespace std;#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long#define db double#define Sz(a) sizeof(a)#define mcl(a,b) memset(a,b,Sz(a))#define mcp(a,b) memcpy(a,b,Sz(b))#define INF 0x3f3f3f3f#define inf 0x7fffffff#define pb push_back#define M 1000005int n,m,q,k;int A[M];LL cnt[M];struct p20{    void solve(){        int cnt=0;        int w=max(n,m);        REP(i,1,n){            REP(j,1,m){                if(i*j>w)break;                A[++cnt]=i*j;            }        }        sort(A+1,A+1+cnt);        while(q--){            scanf("%d",&k);            printf("%d\n",A[k]);        }    }}p20;struct p100{    LL check(int x){        int t=sqrt(x);        LL sum=0;        REP(i,1,min(t,n))sum+=x/i;        REP(i,1,min(t,m))sum+=x/i;        return sum-t*t;    }    void solve(){        while(q--){            scanf("%d",&k);            int L=1,R=k,ans;            while(L<=R){                int mid=(L+R)>>1;                if(check(mid)>=k)ans=mid,R=mid-1;                else L=mid+1;            }            printf("%d\n",ans);        }    }}p100; int main(){//  freopen("kth.in","r",stdin);//  freopen("kth.out","w",stdout);    cin>>n>>m>>q;    if(n<=1000 && m<=1000)p20.solve();    else p100.solve();    return 0;}

num ——3821

思路:这是一道十分水的题目,只是考试时没有去想正解,太关心大暴力了…
此题唯一的烦点就在m次询问,且每次标记一个点,而且m的范围蛮大的。

那么我们究其根本,dp的转移只是它的下方和它的下右方,但这层的dp又是从它的上方和它的上左方收集上去的。

也就是说,每一层的转移只与它的上下四个位置有关。
而针对每个标记的xy,我们一定是可以先找出一条原先最优的路,看标记的这个点是否在这条路径上。
若没有,很简单,输出原来路径的最大值;否则,则一定是找一条次优的路径,而这条次优的路径和原路径不同只是在于x层的原路径的点和我们要找的另一个次优的点。

那么就简单了,我们就只需要预处理出每一层的最优路径和次优路径,且标次层最优路径的点和次优路径的点即可。

code

#include<iostream>#include<cstdio>#include<cstring>#include<ctime>#include<cstdlib>#include<algorithm>#include<vector>using namespace std;#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long#define db double#define Sz(a) sizeof(a)#define mcl(a,b) memset(a,b,Sz(a))#define mcp(a,b) memcpy(a,b,Sz(b))#define INF 0x3f3f3f3f#define inf 0x7fffffff#define pb push_back#define N 1005int n,m;LL A[N][N];struct p40{    #define M 55    bool mark[M][M];    LL A[M][M],B[M][M];    LL work(){        mcp(B,A);        DREP(i,n-1,1){            REP(j,1,i){                if(mark[i][j])continue;                if(mark[i+1][j])B[i][j]+=B[i+1][j+1];                else if(mark[i+1][j+1])B[i][j]+=B[i+1][j];                else B[i][j]+=max(B[i+1][j],B[i+1][j+1]);            }        }        return B[1][1];    }    void solve(){        REP(i,1,n)REP(j,1,i)scanf("%lld",&A[i][j]);        while(m--){            int x,y;            scanf("%d%d",&x,&y);            if(x==1 && y==1)puts("-1");            else {                mark[x][y]=1;                printf("%lld\n",work());                mark[x][y]=0;            }        }    }}p40;struct p10{    int s;    bool check(){        s=A[1][1];        REP(i,2,n)REP(j,1,i)if(s!=A[i][j])return 0;        return 1;    }    void solve(){        while(m--){            int x,y;            scanf("%d%d",&x,&y);            if(x==1 && y==1)puts("-1");            else printf("%lld\n",1LL*n*s);        }    }}p10;struct p20{    bool check(){        REP(i,1,n)REP(j,1,i)if(A[i][j]!=i-j)return 0;        return 1;     }    void solve(){        LL ans=1LL*n*(n-1)/2;        while(m--){            int x,y;            scanf("%d%d",&x,&y);            if(x==1 && y==1)puts("-1");            else {                if(y==1)printf("%lld\n",ans-n+x-1);                else printf("%lld\n",ans);              }        }    }}p20;struct p30{    bool check(){        REP(i,1,n)REP(j,1,i)if(A[i][j]!=1LL*i*j)return 0;        return 1;     }    LL sum[N];    LL calc(){        LL res=0;        REP(i,1,n)res+=1LL*i*i,sum[i]=sum[i-1]+i;        return res;    }    void solve(){        LL ans=calc();        while(m--){            int x,y;            scanf("%d%d",&x,&y);            if(x==1 && y==1)puts("-1");            else {                if(x!=y)printf("%lld\n",ans);                else printf("%lld\n",ans-(sum[n]-sum[x-1]));            }        }    }}p30;struct p100{    LL dp1[N][N],dp2[N][N];    LL ans[N][2],Id[N][2];//max_id and second max_id    void Init(){        REP(i,1,n)            REP(j,1,i)                dp1[i][j]=max(dp1[i-1][j-1],dp1[i-1][j])+A[i][j];        REP(i,1,n)dp2[n][i]=A[n][i];        DREP(i,n-1,1)            REP(j,1,i)                dp2[i][j]=max(dp2[i+1][j],dp2[i+1][j+1])+A[i][j];        REP(i,1,n){            REP(j,1,i){                LL now=max(dp1[i-1][j-1],dp1[i-1][j])+max(dp2[i+1][j],dp2[i+1][j+1])+A[i][j];                if(now>=ans[i][0]){                    ans[i][1]=ans[i][0];                    Id[i][1]=Id[i][0];                    ans[i][0]=now;                    Id[i][0]=j;                }                else if(now>=ans[i][1]){                    ans[i][1]=now;                    Id[i][1]=j;                }            }        }    }    void solve(){        Init();        while(m--){            int x,y;            scanf("%d%d",&x,&y);            if(x==1 && y==1)puts("-1");            else printf("%lld\n",y==Id[x][0]?ans[x][1]:ans[x][0]);        }    }}p100;int main(){//  freopen("num.in","r",stdin);//  freopen("num.out","w",stdout);    cin>>n>>m;    if(n<=50)p40.solve();    else {        REP(i,1,n)REP(j,1,i)scanf("%lld",&A[i][j]);        if(p10.check())p10.solve();//same         else if(p20.check())p20.solve();//i-j        else if(p30.check())p30.solve();// i*j        else p100.solve();    }    return 0;}

小结:今天的第3题失误太大了…根本没有去想正解,导致看到第3题无脑敲部分分,导致两个部分分的题意看错了…T_T——看完题先想一波暴力,敲完暴力,再花10分钟思考一下正解。

原创粉丝点击