• U197241 ご注文はうさぎですか?和 U197124 大地の閾を探して


    ご注文はうさぎですか?

    HINT:
    总和对7取模只有7种状态,是不是可以把每个生命值下能取到的最大总和记录一下?

    Solve:
    因为总和对7取模只有7个状态,生命值最大1000,所以dp的状态可以第一维记录这个状态对7取模的值,dp数组本身记录当前状态能取到的最大总和

    所以先枚举物品i,再枚举能量h,最后枚举从哪个已存在的总和进行转移
    即:

    dp[i][(j+a[i])%7][h] = max(dp[i][(j+a[i])%7][h], 
    			   dp[i-1][j%7][h - b[i]] + a[i])
    

    可以省略第一维,转移的时候额外开一个tmp记录一下上一个物品的状态即可

    #include<bits/stdc++.h>
    #define ll long long
    #define pii pair<int,int>
    #define pll pair<ll,ll>
    #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
    using namespace std;
    
    const int maxn = 1e5 + 5;
    const int inf = 1e9 + 7;
    const ll lnf = 1e18;
    const ll mod = 998244353;
    
    int a[maxn], b[maxn];
    
    ll dp[7][1005];
    ll tmp[7][1005];
    
    int main()
    {
    	fastio;
    	int n, h;
    	cin >> n >> h;
    	for (int i = 1; i <= n; i++)
    		cin >> a[i];
    	for (int i = 1; i <= n; i++)
    		cin >> b[i];
    	memset(dp, -1, sizeof(dp));
    	memset(tmp, -1, sizeof(tmp));
    	dp[0][0] = 0;
    	tmp[0][0] = 0;
    	for (int i = 1; i <= n; i++) {
    
    		for (int j = 0; j < 7; j++) {
    			for (int k = 0; k <= h; k++) {
    				if (k + b[i] > h)break;
    				if (dp[j][k] == -1)continue;
    				tmp[(j + a[i]) % 7][k + b[i]] = max(tmp[(j + a[i]) % 7][k + b[i]], dp[j][k] + a[i]);
    			}
    		}
    
    		for (int j = 0; j < 7; j++) {
    			for (int k = 0; k <= h; k++) {
    				dp[j][k] = tmp[j][k];
    			}
    		}
    	}
    	ll ans = 0;
    	for (int k = 0; k <= h; k++)
    		ans = max(ans, dp[0][k]);
    	cout << ans;
    	return 0;
    
    }
    

    大地の閾を探して

    建议直接拉到最下面看题意

    image

    本质上是两个题:

    • 从树上选m条边,边与边之间没有公共点的方案数
    • 剩下2n-2m个点两两自由组合的方案数

    这两个贡献乘在一起就可以了

    • 对于第一个题(建议直接看代码):
      树上背包,记录每个点是否选取子树临边的状态下,以它为根的子树选了x条边的方案数

      dp数组记录的是对于父节点from枚举完to之前所有子树的方案数,现在需要将to带来的贡献转移到答案中,需要临时数组g记录转移后的结果(直接在dp上加的话会导致子树to自己的贡献相互作用),在将g复制给dp。

      // from和to都没选
      g[i + j][0] += dp[from][i][0] * (dp[to][j][0] + dp[to][j][1]) % mod;
      g[i + j][0] %= mod;
      
      // from在枚举to之前已经选了
      g[i + j][1] += dp[from][i][1] * (dp[to][j][0] + dp[to][j][1]) % mod;
      g[i + j][1] %= mod;
      
      // 选from和to相连的这条边
      g[i + j + 1][1] += dp[from][i][0] * dp[to][j][0] % mod;
      g[i + j + 1][1] %= mod;
      
    • 第二个题:
      递推,有n-1个数,多加入1个数,这个数和前面所有数配对(n-1),剩下的数两两配对(f[n-2])
      即:$f_n =(n-1) \cdot f_{n-2} $

    #include<bits/stdc++.h>
    #define ll long long
    #define pii pair<int,int>
    #define pll pair<ll,ll>
    #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
    using namespace std;
    
    const int maxn = 3e5 + 5;
    const int inf = 1e9 + 7;
    const ll lnf = 1e18;
    const ll mod = 998244353;
    
    vector<int>G[maxn];
    
    ll dp[4005][2005][2];
    ll g[2005][2];
    int siz[maxn];
    
    void dfs(int from, int fa) {
    	siz[from] = 1;
    	dp[from][0][0] = 1;
    	for (auto to : G[from]) {
    		if (to == fa)continue;
    		dfs(to, from);
    		for (int i = 0; i <= (siz[from]+ siz[to]) / 2; i++)
    			g[i][0] = 0, g[i][1] = 0;
    		for (int i = 0; i <= siz[from] / 2; i++)
    			for (int j = 0; j <= siz[to] / 2; j++) {
    				g[i + j][0] += dp[from][i][0] * (dp[to][j][0] + dp[to][j][1]) % mod;
    				g[i + j][0] %= mod;
    				g[i + j][1] += dp[from][i][1] * (dp[to][j][0] + dp[to][j][1]) % mod;
    				g[i + j][1] %= mod;
    				g[i + j + 1][1] += dp[from][i][0] * dp[to][j][0] % mod;
    				g[i + j + 1][1] %= mod;
    			}
    		siz[from] += siz[to];
    		for (int i = 0; i <= siz[from] / 2; i++)
    			dp[from][i][0] = g[i][0], dp[from][i][1] = g[i][1];
    		/*cout << from << ":" << endl;
    		for (int i = 0; i <= siz[from] / 2; i++)
    			cout << dp[from][i][0] << " ";
    		cout << endl;
    		for (int i = 0; i <= siz[from] / 2; i++)
    			cout << dp[from][i][1] << " ";
    		cout << endl << endl;*/
    
    	}
    
    }
    
    ll f[maxn];
    
    int main()
    {
    	fastio;
    	int n, m;
    	cin >> n >> m;
    	for (int i = 1; i < 2 * n; i++) {
    		int x, y;
    		cin >> x >> y;
    		G[x].push_back(y);
    		G[y].push_back(x);
    	}
    	dfs(1, 0);
    	f[1] = 1;
    	f[2] = 1;
    	for (int i = 3; i <= 2 * n; i++)
    		f[i] = f[i - 2] * (i - 1) % mod;
    	cout << (dp[1][m][0] + dp[1][m][1]) * f[2 * n - 2 * m] % mod;
    
    	return 0;
    
    }
    
  • 相关阅读:
    [转][Navicat for MySQL系列]Navicat如何使用(二)
    [转]Syntax error on token "Invalid Character", delete this token 的解决
    [转] valuestack,stackContext,ActionContext.之间的关系
    [转]jquery后代和子元素的区别
    python中模块、包、库的区别和使用
    python函数对象
    list深拷贝和浅拷贝
    json中load和loads区别
    变量作用域
    正则里的.*和.*?区别
  • 原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/16216376.html
Copyright © 2020-2023  润新知