【考试反思】联赛模拟测试15

建议改成:凯爹吊打 std

凯爹被卡常了,可恶啊。

基础篇,但成功暴露了基础很薄弱。T4 LCIS 完全没思路。

T1: 90 ( ightarrow) 80

T1:游戏

对自己暴力太自信了,想数据点分治,但显然 (O(10!cdot 10)) 显然是跑不过 500ms的 = =。

其实也不好意思说是挂分,因为是乱搞的水了很多分。对拍大概每 3000,4000 组就挂了,但是数据太水,就很偷税

正解是和之前的哪一天她能重回我身边类似,但没有疾患鼠的情况所以更简单。同样两个值连边,统计联通块大小。以上口胡的

正解是并查集。一个装备的两个属性连到并查集里,如果并查集构成了一个环,那么这个并查集是可以都选的。如果并查集构成了一棵树,那么这个并查集除了最大的数都可以选。

从一开始循环选就好了,当选不了了就 break。(%%% HISKrrr

Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int n,ans;

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int fa[maxn],siz[maxn];
bool flag[maxn];//判断是否为环
int Find(int x){
    return x==fa[x]?x:(fa[x]=Find(fa[x]));
}

int main(){
#ifndef LOCAL
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
#endif
    n=read();
    for(int i=1;i<=10000;i++){
        fa[i]=i;
        siz[i]=1;
    }
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        int fax=Find(x),fay=Find(y);
        if(fax==fay){
            flag[fax]=1;
        }else{
            fa[fax]=fay;
            siz[fay]+=siz[fax];
            flag[fay]|=flag[fax];
        }
    }
    for(int i=1;i<=10000;i++){
        int fai=Find(i);
        if((flag[fai]&&siz[fai]>0)||siz[fai]>1){
            ans++;siz[fai]--;
        }else break;
    }
    printf("%d
",ans);
    return 0;
}

T2:嘟嘟噜

约瑟夫问题,但显然线性是过不去的。

打表发现(建议 (m)(4),很容易找到规律),只有过了一段区间之后才会出现取模的情况,那就是目前的值比下标大的时候。那么我们显然可以计算出下次跳到需要取模的位置,中间直接乘法加上。

设下一次需要跳 (x) 步,目前的值是 (a),那么可以得到:

[i+x<a+m imes x ]

首先注意一定是小于,因为正好相等的时候是不能取模的,因为实际上正好相等的时候对应到 (0) ~ (n-1) 的编号是比下标小的。

简单移项改等号解得:

[x=igglceil cfrac{i-a}{m-1} igg ceil ]

那么下次的下标就是 (i+x)。相等的时候需要特判一下,懂的都懂。

最后剩下的部分直接加上就好了。小于 (m) 的部分直接暴力。

时间复杂度 (O(能过))

当然前提是你要会线性解决约瑟夫问题的式子,可以看前几天的那道题。

UPD:现在我发现在一开始如果不 (+1) 的话就不用特判了 orz

Code
#include <bits/stdc++.h>
using namespace std;

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

int main(){
#ifndef LOCAL
    freopen("mayuri.in","r",stdin);
    freopen("mayuri.out","w",stdout);
#endif
    int T=read();
    while(T--){
        int n=read(),m=read(),x=0,i=m;
        for(register int j=2;j<=min(n,m);j++){
            x=(x+m)%j;
        }
        if(n<=m)printf("%d
",x+1);
        else{
            x+=1;//记得+1!
            while(1){
                int nxt=i+(int)ceil(1.0*(i-x)/(m-1));
                if(nxt>n)break;
                x=(x+(nxt-i)*m);
                if(x==nxt){
                    if(++nxt>n)break;
                    x=(x+m)%nxt;
                }else x%=nxt;
                i=nxt;
            }
            x+=(n-i)*m;
            printf("%d
",x);
        }
    }
    return 0;
}

T3:天才绅士少女助手克里斯蒂娜

好像直接改改式子,就能用线段树单点修改区间求和了。但是 T2 调了太久,所以本题 10 min 走人 = =。

[egin{aligned} sumlimits_{lleq i<jleq r}vert v_i imes v_jvert^2&= sumlimits_{lleq i<jleq r}(x_iy_j-x_jy_i)^2\ &=sumlimits_{lleq i<jleq r}x_i^2y_j^2-2 imes x_iy_ix_jy_j+x_j^2y_i^2\ &=sumlimits_{i=l}^rsumlimits_{j=l}^r x_i^2y_j^2-x_iy_ix_jy_j\ &=igg(sumlimits_{i=l}^rx_i^2igg) imes igg(sumlimits_{i=l}^ry_i^2igg)-igg(sumlimits_{i=l}^rx_iy_iigg)^2\ end{aligned}]

直接开线段树维护 (x^2)(y^2)(xy) 即可。

不开 long long 见祖宗

Code
#include <bits/stdc++.h>
using namespace std;
int n,m;
long long X2,Y2,XY;
const int Mod=20170927;
const int maxn=1e6+10;

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

struct Node{
    long long x,y;
}v[maxn];

#define lson (rt<<1)
#define rson (rt<<1|1)
struct SEG{
    long long x2,y2,xy;
}tree[maxn<<2];

inline void pushup(int rt){
    tree[rt].x2=(tree[lson].x2+tree[rson].x2)%Mod;
    tree[rt].y2=(tree[lson].y2+tree[rson].y2)%Mod;
    tree[rt].xy=(tree[lson].xy+tree[rson].xy)%Mod;
}

void build(int rt,int l,int r){
    if(l==r){
        tree[rt].x2=(v[l].x*v[l].x)%Mod;
        tree[rt].y2=(v[l].y*v[l].y)%Mod;
        tree[rt].xy=(v[l].x*v[l].y)%Mod;
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    pushup(rt);
}

void modify(int rt,int l,int r,int p,long long x,long long y){//这的x和y也要开long long!
    if(l==r){
        tree[rt].x2=(x*x)%Mod;
        tree[rt].y2=(y*y)%Mod;
        tree[rt].xy=(x*y)%Mod;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)modify(lson,l,mid,p,x,y);
    else modify(rson,mid+1,r,p,x,y);
    pushup(rt);
}

void query(int rt,int l,int r,int s,int t){
    if(s<=l&&r<=t){
        X2=(X2+tree[rt].x2)%Mod;
        Y2=(Y2+tree[rt].y2)%Mod;
        XY=(XY+tree[rt].xy)%Mod;
        return;
    }
    int mid=(l+r)>>1;
    if(s<=mid)query(lson,l,mid,s,t);
    if(t>mid)query(rson,mid+1,r,s,t);
}

int main(){
#ifndef LOCAL
    freopen("kurisu.in","r",stdin);
    freopen("kurisu.out","w",stdout);
#endif
    n=read();m=read();
    for(int i=1;i<=n;i++){
        v[i].x=read();v[i].y=read();
    }
    build(1,1,n);
    while(m--){
        int opt=read();
        if(opt==1){
            int p=read(),x=read(),y=read();
            modify(1,1,n,p,x,y);
        }else{
            int l=read(),r=read();
            X2=Y2=XY=0;
            query(1,1,n,l,r);
            printf("%lld
",((X2*Y2%Mod-(XY*XY)%Mod)%Mod+Mod)%Mod);
        }
    }
    return 0;
}

T4:凤凰院凶真

LCIS 并输出方案,爷不会(wtcl)。

奉上金牌教练老姚版 LCIS:

Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+10;
int n,m;
int a[maxn],b[maxn];
int f[maxn][maxn],pre[maxn][maxn];

inline int read(){
    int x=0;bool fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return fopt?x:-x;
}

void Print(int x,int y){
    if(!x)return;
    Print(x-1,pre[x][y]);
    if(f[x][y]!=f[x-1][pre[x][y]])
        printf("%d ",b[y]);
}

int main(){
#ifndef LOCAL
    freopen("phoenix.in","r",stdin);
    freopen("phoenix.out","w",stdout);
#endif
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    m=read();
    for(int i=1;i<=m;i++)
        b[i]=read();
    for(int i=1;i<=n;i++){
        int Max=0,k=0;
        for(int j=1;j<=m;j++){
            f[i][j]=f[i-1][j];pre[i][j]=j;
            if(a[i]>b[j]&&Max<f[i-1][j]){
                Max=f[i-1][j];k=j;
            }
            if(a[i]==b[j]){
                f[i][j]=Max+1;pre[i][j]=k;
            }
        }
    }
    int now=0;
    for(int i=1;i<=m;i++)
        if(f[n][i]>f[n][now])now=i;
    printf("%d
",f[n][now]);
    Print(n,now);
    puts("");
    return 0;
}
原文地址:https://www.cnblogs.com/Midoria7/p/13807834.html