zoukankan      html  css  js  c++  java
  • [Codeforces Round #642 (Div. 3)] ABCDEF题解

    [Codeforces Round #642 (Div. 3)] ABCDEF题解

    A. Most Unstable Array

    思路:

    (n=1)时答案为( ext 0)

    (n=2)时答案为(mathit n)

    (n=3)时答案为(2*n)

    代码:
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		ll n, k;
    		n = readll();
    		k = readll();
    		if (n == 1)
    		{
    			printf("0
    ");
    		} else if (n == 2)
    		{
    			printf("%lld
    ", k);
    		} else
    		{
    			printf("%lld
    ", k * 2ll );
    		}
    	}
     
    	return 0;
    }
     
    

    B. Two Arrays And Swaps

    思路:

    简单贪心,对数组(a,b)分别sort之后,当前数组(mathit b)中的最大值比数组(mathit a)中的最小值大时让其交换。

    代码:
    int n;
    int k;
    int a[maxn];
    int b[maxn];
     
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		n = readint();
    		k = readint();
    		int sum = 0;
    		repd(i, 1, n)
    		{
    			a[i] = readint();
    			sum += a[i];
    		}
    		repd(j, 1, n)
    		{
    			b[j] = readint();
    		}
    		sort(a + 1, a + 1 + n);
    		sort(b + 1, b + n + 1);
    		repd(i, 1, k)
    		{
    			if (a[i] < b[n - i + 1])
    			{
    				sum += b[n - i + 1] - a[i];
    			}
    		}
    		printf("%d
    ", sum );
    	}
     
    	return 0;
    }
    

    C. Board Moves

    思路:

    手花一下样例(n=5),可以发现,每一个cell都移动到最中间的((frac{n+1}{2},frac{n+1}{2}))的cell消耗最小。

    而cell移动的成本是切比雪夫距离:

      平面上两个点((x1,y1),(x2,y2))之间的距离为(max( |x1-x2 | , | y1 - y2 | ))

    而切比雪夫距离会随着cell的(max(i,j))在变化,所以枚举一下(max(i,j))即可。

    代码:
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		int n = readint();
    		ll ans = 0ll;
    		repd(i, 2, (n + 1) / 2)
    		{
    			ans += 1ll * ((i + i - 1) * 4ll - 4) * (i - 1);
    		}
    		printf("%lld
    ", ans );
    	}
     
    	return 0;
    }
    

    D. Constructing the Array

    思路:

    维护一个以区间长度更大为第一标准,以区间的左端点值更小为第二标准的优先队列,然后模拟下题意即可。

    代码:
    
    const int maxn = 1000010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    #define DEBUG_Switch 0
    struct node
    {
    	int l, r;
    	int len;
    	node() {}
    	node(int __l, int __r)
    	{
    		l = __l;
    		r = __r;
    		len = r - l + 1;
    	}
    	bool operator < (const node & b) const
    	{
    		if (len != b.len)
    		{
    			return len < b.len;
    		} else
    		{
    			return l > b.l;
    		}
    	}
    };
    priority_queue<node> q;
    int a[maxn];
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		int n = readint();
    		q.push(node(1, n));
    		int id = 1;
    		while (!q.empty())
    		{
    			node temp = q.top();
    			q.pop();
    			int l = temp.l;
    			int r = temp.r;
    			if (temp.len & 1)
    			{
    				a[(temp.r + temp.l) / 2] = id++;
    				int mid = (temp.r + temp.l) / 2;
    				if (l <= mid - 1)
    				{
    					q.push(node(l, mid - 1));
    				}
    				if (mid + 1 <= r)
    				{
    					q.push(node(mid + 1, r));
    				}
    			} else
    			{
    				a[(temp.r + temp.l - 1) / 2] = id++;
    				int mid = (temp.r + temp.l - 1) / 2;
    				if (l <= mid - 1)
    				{
    					q.push(node(l, mid - 1));
    				}
    				if (mid + 1 <= r)
    				{
    					q.push(node(mid + 1, r));
    				}
    			}
    		}
    		repd(i, 1, n)
    		{
    			printf("%d%c", a[i], i == n ? '
    ' : ' ' );
    		}
    	}
    
    	return 0;
    }
    
     
    

    E. K-periodic Garland

    思路:

    枚举([0,k-1])作为目标亮灯位置(index)(mathit k)取模后的数值,

    然后通过预处理过的前缀和算出有多少灯必须灭掉,

    对于剩余的亮灯部分通过动态规划来求解操作次数最小的满足条件情况。

    定义状态:

    (dp[i][0])代表到第(i)个以及之前所有的灯都是灭掉时的最小成本。

    (dp[i][1])代表到第(i)个灯时,只有(mathit i) 以及之前若干灯(可能为0)为点亮时的最小成本。

    转移方程见代码。

    在通过处理一个后缀和维护就可以动态规划转移时得到答案。

    代码:
    int a[maxn];
    int n, k;
    int sum[maxn];
    std::vector<int> v;
    int cnt[maxn];
    int dp[maxn][2];
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		n = readint();
    		k = readint();
    		repd(i, 1, n)
    		{
    			scanf("%1d", &a[i]);
    		}
    		repd(i, 1, n)
    		{
    			sum[i] = sum[i - 1] + a[i];
    		}
    		// special
    		if (n == 1)
    		{
    			printf("0
    ");
    			continue;
    		}
    		// else
    		int ans = n;
    		repd(i, 1, k)
    		{
    			int now = 0;
    			int j;
    			v.clear();
    			v.pb(0);
    			for (j = i; j <= n; j += k)
    			{
    				v.pb(a[j]);
    				now += sum[j - 1] - sum[max(j - k, 0)];
    			}
    			if (j > n) {
    				j -= k;
    				now += sum[n] - sum[j];
    			}
    			int len = sz(v) - 1;
    			for (j = len; j >= 1; --j)
    			{
    				cnt[j] = cnt[j + 1] + v[j];
    			}
    			int w = inf;
    			for (j = 1; j <= len; ++j)
    			{
    				if (v[j] == 1)
    				{
    					dp[j][1] = min(dp[j - 1][1], dp[j - 1][0]);
    					dp[j][0] = dp[j - 1][0] + 1;
    				} else
    				{
    					dp[j][1] = min(dp[j - 1][1] + 1, dp[j - 1][0] + 1);
    					dp[j][0] = dp[j - 1][0];
    				}
    				w = min(w, min(dp[j][1], dp[j][0]) + min(cnt[j + 1], (n - j) - cnt[j + 1]));
    			}
    			now += w;
    			ans = min(ans, now);
    			// clear
    			for (j = 1; j <= len; ++j)
    			{
    				cnt[j] = 0;
    				dp[j][0] = dp[j][1] = 0;
    			}
    		}
    		printf("%d
    ", ans );
    	}
     
    	return 0;
    }
     
    

    F. Decreasing Heights

    思路:

    通过分析可以发现,最优路径中一定有一个cell的height是固定值(没有被改变)。

    那么我们不妨枚举每一个cell作为那个height是固定值的cell,然后计算当前约束下的最小花费。

    设当前枚举的cell坐标为((x,y)),则计算方法为:

    (dp[i][j])代表从((x,y))移动到((i,j))时的最小花费。

    (b[i][j])代表从((x,y))移动到((i,j))时的,cell((i,j))的height。

    转移方程见代码。

    枚举部分的时间复杂度为:(O(n*m))

    计算部分的时间复杂度为:(O(n*m))

    所以总时间复杂度为:(O(n^2*m^2)).

    代码:
    int n, m;
    ll a[maxn][maxn];
    ll dp[maxn][maxn];
    ll b[maxn][maxn];
    const ll INF = 1e18;
     
    ll solve(int x, int y)
    {
    	repd(i, 0, n + 1)
    	{
    		repd(j, 0, m + 1)
    		{
    			dp[i][j] = 1e18;
    			b[x][y] = 1e18;
    		}
    	}
    	dp[x][y] = 0ll;
    	b[x][y] = a[x][y];
    	for (int i = x; i >= 1; --i)
    	{
    		for (int j = y; j >= 1; --j)
    		{
    			if (i == x && j == y)
    				continue;
    			if (a[i][j] >= b[i + 1][j] - 1 && dp[i][j] > dp[i + 1][j] + (a[i][j] - b[i + 1][j] + 1) )
    			{
    				dp[i][j] = dp[i + 1][j] + (a[i][j] - b[i + 1][j] + 1) ;
    				b[i][j] = b[i + 1][j] - 1;
    			}
    			if (a[i][j] >= b[i][j + 1] - 1 && dp[i][j] > dp[i][j + 1] + (a[i][j] - b[i][j + 1] + 1) )
    			{
    				dp[i][j] = dp[i][j + 1] + (a[i][j] - b[i][j + 1] + 1) ;
    				b[i][j] = b[i][j + 1] - 1;
    			}
    		}
    	}
    	for (int i = x; i <= n; ++i)
    	{
    		for (int j = y; j <= m; ++j)
    		{
    			if (i == x && j == y)
    				continue;
    			if (a[i][j] >= b[i - 1][j] + 1 && dp[i][j] > dp[i - 1][j] + (a[i][j] - b[i - 1][j] - 1) )
    			{
    				dp[i][j] = dp[i - 1][j] + (a[i][j] - b[i - 1][j] - 1) ;
    				b[i][j] = b[i - 1][j] + 1 ;
    			}
    			if (a[i][j] >= b[i][j - 1] + 1 && dp[i][j] > dp[i][j - 1] + (a[i][j] - b[i ][j - 1] - 1) )
    			{
    				dp[i][j] = dp[i][j - 1] + (a[i][j] - b[i ][j - 1] - 1) ;
    				b[i][j] = b[i][j - 1] + 1 ;
    			}
    		}
    	}
    	return dp[1][1] + dp[n][m];
    }
    int main()
    {
    #if DEBUG_Switch
    	freopen("C:\code\input.txt", "r", stdin);
    #endif
    	//freopen("C:\code\output.txt","r",stdin);
    	int t;
    	t = readint();
    	while (t--)
    	{
    		ll ans = 1e18;
    		n = readint();
    		m = readint();
    		repd(i, 1, n)
    		{
    			repd(j, 1, m)
    			{
    				a[i][j] = readll();
    			}
    		}
    		repd(i, 1, n)
    		{
    			repd(j, 1, m)
    			{
    				ans = min(ans, solve(i, j));
    			}
    		}
    		printf("%lld
    ", ans );
    	}
     
    	return 0;
    }
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    HDU 1251 统计难题(字典树模板题)
    POJ 1182 食物链(带权并查集)
    FJUT 2351 T^T的图论(并查集)
    10.QT程序框架与connect
    9.正则表达式
    8.QList QMap QVariant
    7.treeview
    6.图形化列表查询显示
    5.listview(QStringList QStringListModel)
    4.QList
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12896280.html
Copyright © 2011-2022 走看看