1011練習賽


 1011練習賽

總結

 

T1倒是很簡單幾分鍾就切了。
T2把考察內容搞錯了,一開始就去想迭代加深了,饒了很大個彎。
重新想呢,把性質分析的很透徹,可惜沒看出來怎么做。賽后一說是dp,瞬間明朗了。。。。。
T3,一道好難的dp,當時想出了“至少有一人給出的球為0”,但是又陷入了怎么去重的問題。。。最終就不太敢寫了,只有一點暴力。
T4,這次kzsn做得很好,很努力地分析了樣例,並且知道了這道題簡化后的式子“求[i-t,i]的最大值,以及求和”。
不過就沒更多進展了。

課下重寫這些題時也有了些想法。
T1:居然TLE了,后來想想,像這樣的暴力題,還是得用復雜度最好跑不滿的方法,不然下次TLE就是在賽場上了。

T2:一定要注意數組大小,嚴格根據題目給出的大小來開數組,有時連3開到5都會MLE!!!切記。

T3:取模別嫌多,這樣才不會WA。同時也收獲了一點點小知識,像“平方和”這樣需要除以6的式子,可以判斷n%3的余數來直接除法,可以免一個逆元。

T4: 數據結構中有各種細節,尤其注意數組到負數。
不過T4寫后感覺格外的好玩,因為它巧妙地用數學直線方程來做,以前沒見過這種,挺有意思的。

總而言之,這次考的不太好,但是很好的把暴力分拿滿了。。。(這好像也不算是優點)

 

 

 

T1:[模擬賽20211011]F NKOJ8686

給你兩個數列ai,bi,你要找到一個排列p,使得每個a[i]^b[pi]=x都相等。
你要輸出所有可能的x。

數據范圍:
1<=n<=2000;0<=ai,bi<=10^9

  這道題可以各種做,map,離散化等。

  但是,像寫這種題的時候,如果可能一定要寫復雜度較優秀或者跑不滿的方法,千萬不要嫌麻煩!

(像我,之后在NKOJ上交的時候,TLE起飛)

 

#include<bits/stdc++.h>
using namespace std;
#define re register int
int n,LA,LB,a[2005],b[2005],c[2005];
int ans[4000006], ansnum;
int main()
{
    scanf("%d",&n);
    for(re i=1;i<=n;++i) scanf("%d",&a[i]);
    sort(a+1,a+n+1),LA=unique(a+1,a+n+1)-(a+1);
    for(re i=1;i<=n;++i) scanf("%d",&b[i]);
    sort(b+1,b+n+1),LB=unique(b+1,b+n+1)-(b+1);
    if(LA!=LB)return puts("0"),0;
    for(re i=1,x;i<=LA;++i)
    {
        x=a[1]^b[i];
        int flag=0;
        for(re j=1;j<=LA;++j)c[j]=a[j]^x;
        sort(c+1,c+LA+1);
        for(re j=1;j<=LA;++j)if(b[j]!=c[j]){flag=1;break;}
        if(!flag) ans[++ansnum]=x;
    }
    printf("%d\n",ansnum);
    for(re i=1;i<=ansnum;++i) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

T2:[模擬賽20211011]S NKOJ8687

此處出鍋,不能絕對值算貢獻,得用逆序對,kzsn以后改!!!

有 n 個球,每個球有 RGY 三種顏色。
現在小 F 覺得如果有兩個相鄰的球顏色相同很丑。
他每次可以交換相鄰兩個球,問至少交換多少次才能不丑。

數據范圍:n<=400

先想一想,如果我們知道最終這個序列長什么樣,那么最少需要交換多少次呢?

在草稿紙上畫一畫可以知道,這樣的答案就是 $ans = (sigma | 相應小球原有位置 - 當前位置 |) / 2$;

這里的相應小球指的是:如果這是最終序列的第$i$個‘A’,那么相應小球就是原有序列的第$i$個‘A’

所以我們可以預先處理出第$i$個‘A’的位置。

然后就可以dp了!

f[a][b][c][0/1/2]表示當前重構的序列已經有了a個R,b個G,c個Y,最后一位是RGY中的一個。

就會發現這個方程特別好轉移!

f[a+1][b][c][0] = min(f[a][b][c][k!=0]),以此類瑞!

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=405, INF=0x3f3f3f3f;
char a[N];
inline int gt(char x){if(x=='R')return 0;if(x=='G')return 1;return 2;}
int f[N][N][N][3];
int G[N][N], num[3];
signed main()
{
    int n;
    scanf("%d",&n);
    scanf("%s",&a[1]);
    for(re i=1;i<=n;++i)
    {
        int t=gt(a[i]);
        G[t][num[t]]=i;
        num[t]++;
    }
    int na=num[0], nb=num[1], nc=num[2];
    memset(f, 0x3f, sizeof f);
    f[0][0][0][0]=f[0][0][0][1]=f[0][0][0][2]=0;
    for(re tot=0;tot<n;++tot)
    {
        for(re a=0;a<=tot && a<=na;++a)
        {
            for(re b=0;b<=tot && b<=nb && a+b<=tot;++b)
            {
                int c=tot-a-b;
                if(0<=c && c<=tot && c<=nc)
                {
                    for(re k=0;k<3;++k)
                    {
                        if(f[a][b][c][k]==INF)continue;
                        if(k!=0&&a<na)f[a+1][b][c][0]=min(f[a+1][b][c][0], f[a][b][c][k]+abs(a+b+c+1-G[0][a]));
                        if(k!=1&&b<nb)f[a][b+1][c][1]=min(f[a][b+1][c][1], f[a][b][c][k]+abs(a+b+c+1-G[1][b]));
                        if(k!=2&&c<nc)f[a][b][c+1][2]=min(f[a][b][c+1][2], f[a][b][c][k]+abs(a+b+c+1-G[2][c]));
                    }    
                }
            }
        }
    }
    int ans=min(f[na][nb][nc][0],min(f[na][nb][nc][1],f[na][nb][nc][2]));
    printf("%d", ans==INF?-1:ans/2);
    return 0;
}
View Code

 T3見這里 ,由於kzsn只是懂了,但不太能完美描述,所以。。。nkxjlym yyds

T4 :[模擬賽20211011]o NKOJ8689

有 n 個草堆堆,每個草堆堆燃起了 ai 亮度的火苗。
每個時刻,會有風從左往右吹,
對於每個 ai,會變成 max(ai-1,ai)(同時變)。
默認 a0 = 0。 
有 q 次詢問,問 t 時刻,[l, r] 中火苗的亮度和。初始是 0 時刻。

這道題非常有意思!我維護了個直線的斜率和截距!

將ai隨着時間t變化而變化的圖像畫出來可以知道(這里就參考其他人的博客了,kzsn不太會畫圖)

 

 以上是巨佬的題解,我就是這樣做的,再稍加補充吧。

我們要求vi的前綴和,就可以用樹狀數組維護pi的前綴和以及qi的前綴和。

但由於pi和qi直接維護不太好維護,所以我又定義了個L[i]和R[i],表示圖上的左右兩邊的斜率和截距。

這樣的話,v[i]=R[i]-L[i],q和p就是vi的斜率截距。

至於在哪里需要將表達式更改,肯定是在L[i] “i==li+t+1”時更改,另一邊R[i]一樣的。

最終的答案就是ai的部分在內以及pi-1的前綴和+qi-1的前綴和*t。

總而言之,用樹狀數組維護斜率前綴和以及截距前綴和。

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define int long long

const int N=2e5+5;
int a[N], Q[N], l[N], r[N], lg[N], g[N][25], ans[N], n;
inline int ST(int x, int y){
    int s=lg[y-x+1];
    if(a[g[x][s]] > a[g[y-(1<<s)+1][s]])return g[x][s];
    else return g[y-(1<<s)+1][s];
}
struct BIT{
    int c[N];
    inline int lowbit(int x){return x&-x;}
    inline int getsum(int x){
        int ret=0;
        while(x>0)ret+=c[x],x-=lowbit(x);
        return ret;
    }
    inline void insert(int x,int d){
        while(x<=n)c[x]+=d,x+=lowbit(x);
    }
}B1, B2;
struct node{int k, b;}L[N], R[N], V[N];
struct cag{int type, id;node nw;};
vector<cag>G[N];
inline void update(int i){
    B1.insert(i, -V[i].k);
    B2.insert(i, -V[i].b);
    V[i]=(node){(R[i].k-L[i].k)*a[i], (R[i].b-L[i].b+1)*a[i]};
    B1.insert(i, V[i].k);
    B2.insert(i, V[i].b);
    if(V[i].k<0)
    {
        V[i].k=-V[i].k;
        int t=(V[i].b/V[i].k)+1;
        if(t)
        {
            G[t].push_back((cag){0, i, (node){0, 0}});
            G[t].push_back((cag){1, i, (node){0, -1}});
        }
        V[i].k=-V[i].k;
    }
}
inline int solve(int p, int t){
    int i=ST(max(1ll, p-t), p);
    return B2.getsum(i-1)+B1.getsum(i-1)*t+(p-(L[i].k*t+L[i].b)+1)*a[i];
}

struct qury{
    int t, l, r, id;
    inline bool operator<(const qury&p)const{
        return t<p.t;
    }
}qry[N];
signed main()
{
    int m;
    scanf("%lld%lld",&n,&m);
    for(re i=1;i<=n;++i){
        scanf("%lld",&a[i]);
        g[i][0]=i;
        if(i>1)lg[i]=lg[i>>1]+1;
    }
    for(re i=1;i<=20;++i)
        for(re j=1;j+(1<<i)-1<=n;++j)
            if(a[g[j][i-1]] > a[g[j+(1<<(i-1))][i-1]])g[j][i]=g[j][i-1];
                else g[j][i]=g[j+(1<<(i-1))][i-1];

    for(re i=1, h=0; i<=n; ++i){
        while(h && a[Q[h]]<=a[i])h--;
        l[i]=Q[h];
        Q[++h]=i;
    }
    for(re i=n, h=0; i; --i){
        while(h && a[Q[h]]<a[i])h--;
        r[i]=Q[h];if(!r[i])r[i]=n+1;
        Q[++h]=i;
    }
    for(re i=1;i<=n;++i){
        L[i]=(node){0,i};
        R[i]=(node){1,i};
        update(i);
        if(l[i])G[i-l[i]-1].push_back((cag){0, i, (node){1, l[i]+1}});//Äĸö¶Ëµã£¬¸üгÉʲôÑù
        G[r[i]-i-1].push_back((cag){1, i, (node){0, r[i]-1}});
    }
    for(re i=1;i<=m;++i)scanf("%lld%lld%lld",&qry[i].t,&qry[i].l,&qry[i].r), qry[i].id=i;
    sort(qry+1, qry+1+m);
    int t=-1;
    for(re i=1;i<=m;++i)
    {
        while(t<qry[i].t)
        {
            t++;
            for(cag x:G[t])
            {
                if(x.type==0)//ÐÞ¸Ä×ó¶Ëµã
                {
                    L[x.id]=x.nw;
                    update(x.id);
                }
                else
                {
                    R[x.id]=x.nw;
                    update(x.id);
                }
            }
        }
        ans[qry[i].id] = solve(qry[i].r, t)-solve(qry[i].l-1, t);
    }
    for(re i=1;i<=m;++i)printf("%lld\n", ans[i]);
    return 0;
}

特別有意思!!當然我發現有人居然只用了1000B就寫完了這道題,那些巨佬太強了,而且看不懂。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM