• [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/ 希望所写的文章对您有帮助。
  • 相关阅读:
    Linux用户行为日志审计
    日志分析-Web
    secedit.exe 本地审核
    StreamCQL
    一个关于缓存很好的文章~
    Java免费开源数据库、Java嵌入式数据库、Java内存数据库
    MySQL db优化
    威胁情报
    《javascript设计模式》读书笔记二(封装和隐藏信息)
    Mysql触发器
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12896280.html
Copyright © 2020-2023  润新知