zoukankan      html  css  js  c++  java
  • LOJ #3217. 「PA 2019」Desant(状压dp)

    https://loj.ac/problem/3217

    考虑已经确定了前i个,状态可以只记后面的(n-i)个点之间的(n-i+1)个间隔里的已选的数。

    这个状态最大是(sum_{k=1}^n (n/k)^k)左右,可以发现不是很大。

    注意要用多进制数去存状态,不然会被卡常。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 45;
    
    int n, a[N];
    
    int b[N], b0;
    
    struct nod {
    	ll w0, w[N];
    } p, q;
    
    void build(int *b, int &b0, nod &p) {
    	sort(b + 1, b + b0 + 1);
    	b[0] = 0; b[b0 + 1] = n + 1;
    	p.w0 = b0;
    	p.w[0] = 1;
    	fo(j, 1, b0 + 1) p.w[j] = p.w[j - 1] * (b[j] - b[j - 1]);
    }
    
    void zh(int *a, nod b, int x) {
    	fo(i, 0, b.w0) a[i] = x % b.w[i + 1] / b.w[i];
    }
    
    int zy(int *a, nod b) {
    	int s = 0;
    	fo(i, 0, b.w0) s += a[i] * b.w[i];
    	return s;
    }
    
    struct P {
    	int x; ll y;
    	P(int _x = 0, ll _y = 0) {
    		x = _x, y = _y;
    	}
    };
    
    P operator + (P a, P b) {
    	return a.x == b.x ? P(a.x, a.y + b.y) : (a.x < b.x ? a : b);
    }
    
    vector<P> f[N];
    
    int main() {
    	freopen("a.in", "r", stdin);
    	scanf("%d", &n);
    	fo(i, 1, n) scanf("%d", &a[i]);
    	
    	f[0].resize(1);
    	f[0][0] = P(0, 1);
    	
    	fo(i, 0, n - 1) {
    		b0 = 0;
    		fo(j, i + 1, n) b[++ b0] = a[j];
    		build(b, b0, p);
    		int id; fo(j, 1, b0) if(b[j] == a[i + 1]) id = j;
    			
    		b0 = 0;
    		fo(j, i + 2, n)	b[++ b0] = a[j];
    		build(b, b0, q);
    		
    		int m1 = p.w[p.w0 + 1], m2 = q.w[q.w0 + 1];
    		
    		f[i + 1].resize(m2);
    		ff(k, 0, m2) f[i + 1][k] = P(1e9, 0);
    		
    		ff(k, 0, m1) if(f[i][k].y) {
    			static int c[N], d[N];
    			zh(c, p, k);
    			fo(cho, 0, 1) {
    				P v = f[i][k];
    				if(cho) {
    					fo(u, id, p.w0) v.x += c[u];
    				}
    				int t = -1;
    				fo(u, 0, p.w0) {
    					if(u == id) {
    						d[t] += c[u] + cho;
    					} else d[++ t] = c[u];
    				}
    				int nk = zy(d, q);
    				f[i + 1][nk] = f[i + 1][nk] + v;
    			}
    		}
    	}
    
    	static P ans[N];
    	fo(i, 1, n) ans[i] = P(1e9, 0);	
    	ff(k, 0, f[n].size()) {
    		static int c[N];
    		zh(c, q, k);
    		int x = 0;
    		fo(u, 0, q.w0) x += c[u];
    		ans[x] = ans[x] + f[n][k];
    	}
    	fo(i, 1, n) pp("%d %lld
    ", ans[i].x, ans[i].y);
    }
    
  • 相关阅读:
    SlidingMenu官方实例分析2——BaseActivity
    SlidingMenu官方实例分析1——ExampleListActivity
    SlidingMenu——使用前的配置
    获得String形式日期的后一天
    android中TabHost和RadioGroup
    android中文字斜着显示
    OpenGL ES andoid学习————2
    OpenGL ES andoid学习————1
    Gallery学习————检测手机中是否存在外部存储设备
    Java读取xml数据
  • 原文地址:https://www.cnblogs.com/coldchair/p/12991282.html
Copyright © 2011-2022 走看看