tg 34 solution

T1

\(10pts:\)手玩即可有\(10\)
\(30pts:\)朴素的\(O(n^2)\)模拟即可获得\(30pts\)
\(60pts:\)
\(1.\)\(O(n^2)\)算法基础上选择卡常常数优化即可获得\(60pts\)
\(2.\)如果要优化最坏时间复杂度,考虑\(Splay\)维护区间
可以看做删除+区间平移,单次时间复杂度\(\log n\)
\(100pts:\)
正解显然是线性递推,我们考虑倒着插回去
正着顺时针,反着就是逆时针,于是各种减
首先人数和当前位置前移
然后删除的从上一个位置跳了\(i\)
防止大量循环和减爆零就取个模
最后出的编号就是死的最早的那个,也就是\(1\)

点击查看代码 ``` void work(){ int now=1,tot=1; for(int i=n-1;i;i--){ tot++,now++; now-=i%tot; if(now<=0)now+=tot; } ans=n-now+1; } ```

T2

模拟
\(40pts:\)不用考虑高的问题,所有的操作等价于上下左右平移
\(100pts:\)维护下高指向的情况,考虑全变化就好了,总共\(6\)种但是懒得写了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int o=2222;
int c[o][o],k,n,x[o],y[o],shu,ans;
char ch[o];
void changeN(){
    if(shu==2){
        shu=0;
        y[0]=max(y[k],y[1]);
        for(int i=k;i>=1;i--){
            y[i]=y[0]+1;
        }
        c[x[k]][y[k]]++;
        ans=max(ans,c[x[k]][y[k]]);
    }
    else if(shu==1){
        for(int i=1;i<=k;i++){
            y[i]++;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
    else{
        shu=2;
        for(int i=1;i<=k;i++){
            y[i]=y[k]+i;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
}
void changeE(){
    if(shu==1){
        shu=0;
        x[0]=max(x[k],x[1]);
        for(int i=1;i<=k;i++){
            x[i]=x[0]+1;
        }
        c[x[k]][y[k]]++;
        ans=max(ans,c[x[k]][y[k]]);
    }
    else if(shu==2){
        for(int i=1;i<=k;i++){
            x[i]++;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
    else{
        shu=1;
        for(int i=1;i<=k;i++){
            x[i]=x[k]+i;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
}
void changeW(){
    if(shu==1){
        shu=0;
        x[0]=min(x[k],x[1]);
        for(int i=1;i<=k;i++){
            x[i]=x[0]-1;
        }
        c[x[1]][y[1]]++;
        ans=max(ans,c[x[1]][y[1]]);
    }
    else if(shu==2){
        for(int i=1;i<=k;i++){
            x[i]--;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
    else{
        shu=1;
        for(int i=k;i>=1;i--){
            x[i]=x[1]-i;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
}
void changeS(){
    if(shu==2){
        shu=0;
        y[0]=min(y[k],y[1]);
        for(int i=k;i>=1;i--){
            y[i]=y[0]-1;
        }
        c[x[1]][y[1]]++;
        ans=max(ans,c[x[1]][y[1]]);
    }
    else if(shu==1){
        for(int i=1;i<=k;i++){
            y[i]--;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
    else{
        shu=2;
        for(int i=k;i>=1;i--){
            y[i]=y[1]-i;
            c[x[i]][y[i]]++;
            ans=max(c[x[i]][y[i]],ans);
        }
    }
}
void in(){
    scanf("%d",&k);
    scanf("%s",ch+1);
    for(int i=1;i<=k;i++)x[i]=1000,y[i]=1000;
    c[x[1]][y[1]]=1,ans=1;
}
void work(){
    int len=strlen(ch+1);
    for(int i=1;i<=len;i++){
        if(ch[i]=='N')changeN();
        if(ch[i]=='E')changeE();
        if(ch[i]=='S')changeS();
        if(ch[i]=='W')changeW();
    }
}
void out(){
    if(shu){
        sort(x+1,x+k+1);
        sort(y+1,y+k+1);
        for(int i=1;i<=k;i++)printf("%d ",x[i]-1000);
        puts("");
        for(int i=1;i<=k;i++)printf("%d ",y[i]-1000);
        puts("");
    }
    else{
        printf("%d\n%d\n",x[1]-1000,y[1]-1000);
    }
    printf("%d\n",ans);
    memset(c,0,sizeof(c));
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    memset(ch,0,sizeof(ch));
    shu=0;
}
int main(){
    cin>>n;
    while(n--){
        in();
        work();
        out();
    }
    return 0;
}

T3

不会,但是据说用两个\(ex\)数论板子
不感兴趣了,虽然这两个板子我曾经会过

T4

\(40pts:\)暴力稳过
\(20pts:\)暴力不用担心爆空间
\(10pts:\)暴力不用担心爆时间
\(100pts\):
区间修改,线段树
考虑线段树上区间维护这个东西
如果数不对的话一整个区间直接废掉,我们此时令左标记\(s=-1\)
否则,区间的右标记定为最新值
不合法的情况就是右标记和最新值的差值不为\(1\)

posted @ 2022-08-21 19:37  2K22  阅读(24)  评论(0)    收藏  举报