zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 029C

    AtCoder Grand Contest 029C - Lexicographic constraints

    题目大意

    • 给出一个长为 N N N的序列 A A A,最小化能构造 N N N个字符串满足严格字典序升序且第 i i i个字符串的长度为 A i A_i Ai的字符集大小。
    • N ≤ 2 ∗ 1 0 5 N≤2*10^5 N2105
    • A i ≤ 1 ∗ 1 0 9 A_i≤1*10^9 Ai1109

    题解

    • 最早想的是从左往右直接贪心尽可能小地构造,但是会发现有些时候不能确定怎样才最优。
    • 比如当前 A i = A i + 1 = 3 A_i=A_{i+1}=3 Ai=Ai+1=3,构造到当前的串为“bac”,为了使长度不变且字典序变大,我们并不知道应该加一个字符’d’,变成“bad”,还是直接进位变成“bba”,
    • 那可能会问,变成"bba"不是显然更优吗,其实不一定,万一后面有很多需要进位,进到最后不够了还是需要加’d’,而前面一段的进位是没有‘d’的,也就是说字符集的大小随着构造的过程才增大,到了后面字符集增大后,前面的构造就不是最优的了。
    • 于是想到先二分出一个答案,然后在确定字符集大小的基础上构造,
    • 如果 A i + 1 > A i A_{i+1}>A_i Ai+1>Ai,那么直接在后面补上若干个’a’(最小字符),
    • 否则需要先把多出来的部分去掉,再进行进位操作,
    • 如果进到首位了,那就说明字符集大小不够。
    • 但发现 A i A_i Ai特别大,所以不能一位一位的存,需要连续一段一段的存,相当于是一个栈,这样时间复杂度就可以保证了。
    • 同时要注意的是,可能会有连续进位的情况,要记得循环不断进位,
    • 还要注意栈中可能存在已经被清空的元素,记得删去。

    代码

    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 200010
    int a[N];
    struct {
    	int x, s;
    }st[N];
    int main() {
    	int n, i;
    	scanf("%d", &n);
    	for(i = 1; i <= n; i++) scanf("%d", &a[i]);
    	int l = 1, r = n, ans;
    	while(l <= r) {
    		int mid = (l + r) / 2;
    		int s = 0, t = 0, ok = 1;
    		for(i = 1; i <= n; i++) {
    			if(a[i] > s) {
    				st[++t].x = 1, st[t].s = a[i] - s;
    				s = a[i];
    			}
    			else {
    				int p = 0;
    				while(s > a[i]) {
    					if(s - st[t].s > a[i]) s -= st[t].s, st[t].s--, t--;
    					else {
    						st[t].s -= s - a[i];
    						s = a[i];
    					}
    				}
    				while(st[t].s == 0) t--;
    				p = st[t].x;
    				int j = t; 
    				while(st[j].x == mid && j) j--;
    				if(j == 0) {
    					ok = 0;
    					break;
    				}
    				if(st[j].s == 1) {
    					j = t;
    					while(st[j].x == mid && j) {
    						st[j].x = 1;
    						j--;
    					}
    					st[j].x++;
    				}
    				else {
    					j = t, t++;
    					while(st[j].x == mid && j) {
    						st[j + 1] = st[j];
    						st[j + 1].x  = 1;
    						j--;
    					}
    					st[j + 1].x = st[j].x + 1, st[j + 1].s = 1;
    					st[j].s--;
    				}
    				
    			}
    		}
    		if(ok) ans = mid, r = mid - 1; else l = mid + 1;
    	}
    	printf("%d", ans);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    tomcat安装
    hadoop相关
    kafka Windows安装
    linux安装mysql
    linux安装redis
    linux安装jdk
    netcore kafka操作
    windows文件上传到linux服务器上
    SqlServer索引的原理与应用(转载)
    mssql表分区
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910030.html
Copyright © 2011-2022 走看看