屬實這場考試是順了我的心意
考場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是不是同時被刪去的。如果不是,那麼整...