T3 统计区间

solution

枚举区间右端点,求有几个左端点满足 srsl1=ks_r - s_{l-1} = k

可以用 hash 或者 unordered_map 在枚举时标记前缀和,在标记之前统计左端点数即可

code

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

const int N = 2e5 + 5;

int n , k , a[N] , s[N] , ans;
unordered_map<int , int> mp;

signed main(){
	freopen("tjqj.in" , "r" , stdin);
	freopen("tjqj.out" , "w" , stdout);
	
	cin >> n >> k;
	
	for(int i = 1 ; i <= n ; i ++){
		cin >> a[i];
		
		s[i] = s[i - 1] + a[i];
	}
	mp[0] ++;
	for(int i = 1 ; i <= n ; i ++){
		if(mp[s[i] - k] > 0) ans += mp[s[i] - k];
		mp[s[i]] ++;
	}
	cout << ans;
	return 0;
}

T6 我讨厌非整数

solution

观察数据范围,用 O(n4)O(n^4) 的 dp 求解

注意到题目只要求求平均值是整数的个数,所以我们可以设 dpi,j,kdp_{i,j,k} 表示从 11 ~ iijj 个数并且这 jj 个数的和 modj=k\mod j = k的所有选择可能的个数

显然,状态转移方程需要考虑取 aia_i 和不取 aia_i 两种情况

dpi+1,j,k=dpi+1,j,k+dpi,j,kdp_{i+1,j,k} = dp_{i+1,j,k}+dp_{i,j,k}

(不取 aia_i )

dpi+1,j+1,nk=dpi+1,j+1,nk+dpi,j,kdp_{i+1,j+1,nk} = dp_{i+1,j+1,nk}+dp_{i,j,k}

(取 aia_i)

nk=(k+ai)modjnk = (k + a_i) \mod j

最后注意转移顺序,要先枚举整体的个数,再枚举从 11 ~ nn

code

#include<bits/stdc++.h>
using namespace std;

const int N = 105;
const int mod = 998244353;

int n , a[N] , dp[N][N][N] , ans;

int main(){
	freopen("hate.in" , "r" , stdin);
	freopen("hate.out" , "w" , stdout);
	
	cin >> n;
	
	for(int i = 1 ; i <= n ; i ++){
		cin >> a[i];
	}
	for(int k = 0 ; k <= n ; k ++){
		memset(dp , 0 , sizeof dp);
		dp[1][0][0] = 1;
		
		for(int i = 1 ; i <= n ; i ++){
			for(int j = 0 ; j <= k ; j ++){
				for(int l = 0 ; l < k ; l ++){
					if(!dp[i][j][l]) continue;
					
					dp[i + 1][j][l] = (dp[i + 1][j][l] + dp[i][j][l]) % mod;
					if(j < k){
						int nl = (l + a[i]) % k;
						dp[i + 1][j + 1][nl] = (dp[i + 1][j + 1][nl] + dp[i][j][l]) % mod;
					}
				}
			}
		}
		ans = (ans + dp[n + 1][k][0]) % mod;
	}
	cout << ans;
	return 0;
}