1. 程式人生 > 其它 >如何在網頁中使用響應式影象

如何在網頁中使用響應式影象

前言

\(\texttt{E}\color{red}{\texttt{ricQian}}\) 場切的題,我到現在才來補。

感覺自己做了挺多 \(dp\) 題了,可以嘗試自己做一下。

大意

給你一個長 \(m\) 的陣列 \(v\),要求滿足 \(\operatorname{popcount}(\sum2^{a_i})\le k\)\(a\) 數列的權值和。定義一個數列的權值為 \(\prod v_{a_i}\)

Sol

看到資料範圍很小,考慮高維 \(dp\) 或者狀壓。顯然狀壓沒有前途,考慮設高維的 \(dp\)

然後你考慮題目實際上是讓你對於一個空白的二進位制位,每次可以把一位加一,求最後 \(1\)

的個數不超過 \(k\) 個。我們必須要維護的狀態顯然有當前已經填了幾個 \(1\),然後當前 \(1\) 的個數是多少。這樣我們當前加了一個位置之後,所需要知道的是能進幾位的問題對吧。所以我們還需要維護當前進了幾位,也就是前面填了的 \(1\) 有幾個是因為進位而消失的。

這樣我們有一個初步的想法就是令 \(dp[i][j]\) 表示當前填了 \(i\)\(1\),當前有 \(j\)\(1\) 的權值,這樣不見了的 \(1\) 就是 \(i-j\) 個。

考慮轉移,就是列舉當前填的 \(1\) 是在哪個位置上的,然後我們列舉它進的位數,這樣容易知道上一個狀態的 \(1\) 的個數。然後你發現這點狀態是不夠的,你列舉當前進了幾位,就必須要知道有連續幾個 \(1\)

在當前位的答案。於是你發現這樣的做法好像沒有辦法繼續維護了。

那麼既然是和位數相關,那我不妨從低位向高位去考慮。那由於這樣會對計數沒有順序的過程產生影響,所以我們不妨順序考慮二進位制中的位,然後看當前這位填到 \(a\) 的哪一位去。就是說,我們把 \(dp[i][j][k]\) 表示當前考慮到二進位制第 \(i\) 位,當前有 \(j\)\(1\),並且已經填了 \(a\) 中的 \(k\) 個數的權值和。接著考慮從當前狀態轉移出去,就是你考慮當前位放幾個 \(1\),假設是 \(p\) 個,那麼對 \(j\) 的影響是加上了 \(p\%2\),當然還要加上上一位對當前位的貢獻,所以還需要加上上一位的進位。

因此我們最終確定大炮狀態是 \(dp[i][j][k][d]\) 表示考慮二進位制第 \(i\) 位的時候,此前已經有了 \(j\)\(1\),並且填了 \(a\)\(k\) 個數,且上一位對當前位的進位為 \(p\) 的所有方案的權值和。那麼轉移就比較好想了,就是:

\[dp[i][j][k][d]\times {n-k\choose p}\times v_{i}^p\to dp[i+1][j+(p+d)\%2][k+p][\lfloor\dfrac{p+d}{2}\rfloor] \]

然後暴力轉移,最終答案就是 \(dp[m+1][0\sim k][n][0\sim n]\) 的和。

哦注意最後那個 \(\operatorname{popcount}(d)+j\le k\) 的時候才可以統計入答案。

然後就做完了。

Code

// Problem: P7961 [NOIP2021] 數列
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7961
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// Time: 2022-04-13 21:42:27

#include<bits/stdc++.h>
#define int long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pb push_back
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<'='<<a<<' '
#define pts(a) cerr<<#a<<'='<<a<<'\n'
using namespace std;
const int MOD=998244353;
int ksm(int a,int p){
	int ret=1;while(p){
		if(p&1) ret=ret*a%MOD;
		a=a*a%MOD; p>>=1;
	}return ret;
}
int C[35][35];
void init(){
	C[0][0]=1;
	rep(i,1,33){
		C[i][0]=1; rep(j,1,i)
		C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
	}
}
int dp[110][110][35][35],v[110];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	init();
	int n,m,K;cin>>n>>m>>K;
	rep(i,0,m) cin>>v[i];
	rep(p,0,n) dp[0][p][p][0]=C[n][p]*ksm(v[0],p)%MOD;
	rep(i,0,m) rep(j,0,i) rep(k,0,n) rep(d,0,k){
		// pt(i);pt(j);pt(k);pts(d);
		for(int p=0;p+k<=n;p++){
			// pt(dp[i][j][k][d]);pts(C[n-k][p]);
			// pts(v[i]);
			(dp[i+1][j+(p+d)%2][k+p][(p+d)/2]+=dp[i][j][k][d]*C[n-k][p]%MOD*ksm(v[i],p)%MOD)%=MOD;
		}
	}int ans=0;
	rep(j,0,K) rep(d,0,n){
		if(j+__builtin_popcount(d)>K) continue;
		ans=(ans+dp[m+1][j][n][d])%MOD;
	}cout<<ans<<'\n';
	return 0;
}