省選模擬14

2022-09-20 23:03:12 字數 3865 閱讀 3370

屬實這場考試是順了我的心意

考場200整,第二題掛掉了10分,第三題的暴力dp沒有想到......

第一題不知道我咋了,竟然成功的剪掉了狀態然後切掉了

第二題期望資料是隨的,於是我打了個暴力,期望複雜度\(\mathcal\),最劣複雜度\(\mathcal\)

第三題抓住了一點點性質,但是想偏了,於是只打了暴搜

區間dp,這個演算法是非常顯然的

假設我們已經得到了每個消掉的區間的最大值,那麼我們由乙個簡單的dp就可以得到最後的答案

接下來考慮如何進行區間dp,需要考慮的就是如何把一堆小區間合併

有乙個非常非常暴力的思路就是對於乙個大區間,我們在這個區間內再做乙個dp,也就是dp套dp,總複雜度是\(\mathcal\)

我們去觀察性質,首先發現當前消掉的一定是乙個先上公升後下降的序列,也就是說整個序列可以被分成兩段

那麼這就啟發我們可以在頂點處合併答案,題解做法是正反分別做乙個上公升序列的dp,最後合併就行了

我的也是大同小異,只是把這個需要現成處理的dp用原來的區間dp代表了

最後一維,0表示當前區間最後刪掉的那個是上公升的,1表示是下降的,2表示拐了,3表示前面三個的並

那麼我們只需要列舉在哪個點合併,然後長度的話,我們已經知道了左右端點並且只有單調上公升和單調下降可合併,所以長度減一減就有了

ac_code

#includeusing namespace std;

#define pa pair#define mk(x,y) make_pair(x,y)

#define fi first

#define se second

#define fo(i,x,y) for(int i=(x);i<=(y);i++)

#define fu(i,x,y) for(int i=(x);i>=(y);i--)

int read()

while(isdigit(ch))

return s*t;

}const int inf=0x3f3f3f3f;

const int n=405;

int n,a[n],v[n];

int dp[n][n][5],f[n];

signed main()

fo(i,l+1,r-1)

if(dp[i][r][1]!=-inf)dp[l][r][2]=max(dp[l][r][2],dp[l][i][0]+dp[i][r][1]-v[a[i]-a[l]+1]-v[a[i]-a[r]+1]+v[a[i]-a[l]+a[i]-a[r]+1]);

}if(dp[l][i][1]!=-inf&&dp[i][r][1]!=-inf)

} dp[l][r][3]=max(dp[l][r][0],max(dp[l][r][1],dp[l][r][2]));

fo(i,l+1,r)if(dp[l][i-1][3]!=inf&&dp[i][r][3]!=-inf)dp[l][r][3]=max(dp[l][r][3],dp[l][i-1][3]+dp[i][r][3]);

} memset(f,-0x3f,sizeof(f));f[0]=0;

fo(i,1,n)

} printf("%d",f[n]);

return 0;

}

這個還沒有寫正解,於是把暴力的**貼在這裡

原理就是最短路徑只是一條邊,也就是說我只要維護兩端顏色不同的邊的邊權的最小值就好了

ac_code

#includeusing namespace std;

#define pa pair#define mk(x,y) make_pair(x,y)

#define fi first

#define se second

#define fo(i,x,y) for(int i=(x);i<=(y);i++)

#define fu(i,x,y) for(int i=(x);i>=(y);i--)

int read()

while(isdigit(ch))

return s*t;

}const int n=3e5+5;

int n,m,c,q,col[n];

struct dd[n];

struct ee[n*2];

int head[n],rp;

void add_edg(int x,int y,int z)

setst;

signed main()

fo(i,1,n)col[i]=read();

fo(i,1,m)if(col[d[i].x]!=col[d[i].y])st.insert(mk(d[i].val,i));

while(q--)col[x]=y;

printf("%d\n",st.begin()->fi);

} return 0;

}

設f[i]表示長度為i的合法序列的方案數

轉移的時候就列舉最短的border就好了,如何保證最短?它本身是乙個沒有border的串,也就是我們的f

那麼我們用分治ntt優化轉移就行了,注意這裡不太一樣,我們保證i<=n/2

如果用原來的那種用左邊轉移到右邊那就不好限制了,完全不可行

所以我們用左區間乘右區間貢獻到區間外

還有乙個優化,就是只需要分治前一半,最後再乘一下右區間就好了

ac_code

#includeusing namespace std;

#define int long long

#define fo(i,x,y) for(int i=(x);i<=(y);i++)

#define fu(i,x,y) for(int i=(x);i>=(y);i--)

int read()

while(isdigit(ch))

return s*t;

}const int n=1<<22;

const int mod=998244353;

int ksm(int x,int y)return ret;

}int n,v[n],ans;

int sum[n],inv[n],f[n];

int w[n],af[n],lim,len;

int mo(int x)

void ntt(int *a,int lim)

signed main()

sol(1,n>>1);

int m=n+(n>>1),l=1,mid=n>>1,r=n;

fo(i,0,mid-l)a[i]=f[l+i];

fo(i,mid-l+1,r-l)b[i]=sum[l+i];

for(lim=1,len=0;lim<=m;lim<<=1,len++);

fo(i,0,lim-1)af[i]=(af[i>>1]>>1)|((i&1)<<(len-1));

w[0]=1;w[1]=ksm(3,(mod-1)/lim);

fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;

ntt(a,lim);ntt(b,lim);

w[0]=1;w[1]=ksm(w[1],mod-2);

fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;

fo(i,0,lim-1)a[i]=a[i]*b[i]%mod;

ntt(a,lim);int iv=ksm(lim,mod-2);

fo(i,mid-l+1,min(n-2*l,r+mid-2*l))f[i+2*l]=mo(f[i+2*l]+a[i]*iv%mod);

fo(i,0,lim-1)a[i]=b[i]=0;

printf("%lld",mo(sum[n]-f[n]+mod));

return 0;

}

省選模擬14

t1 要求乙個類似尤拉迴路的東西 考慮其實就是將奇度數點兩兩配對,配對的代價為最短路長度,求最小代價 發現邊權的特殊性 2 i 有乙個很好的性質 sum limits 2 i 2 n 那麼最短路就都是最小生成樹上的路徑 只需要跑出最小生成樹,然後在樹上配對就行了 t2 神題owo 將 i,j i j...

省選模擬14

考慮區間 dp f 表示刪完 l,r 這個區間的最大價值 考慮 l,r 在一次被刪掉 發現好的子串一定是前一段上公升,後一段下降 於是可以再開兩個 g 表示以 l,r 分別為兩個端點中間剩下恰好遞增或遞減的最大價值 那麼可以列舉乙個最大值的位置轉移 l,r 不在一次被刪掉,可以列舉乙個斷點來轉移 因...

省選模擬 14

老規矩,禮尚往來。我覺得題目的英文名字比中文名字好看一些,中文名字就乙個字,好 色 樂。題目要求不一定刪完,如果我們知道強制刪完每個區間的最大價值,剩下的操作就是乙個簡單的 n 2 dp。現在我們只需要求出來刪掉每個區間的最大價值。考慮區間dp。討論區間端點l,r是不是同時被刪去的。如果不是,那麼整...