E. Easy Assembly:https://codeforces.ml/contest/1773/problem/E

大意是给出n个塔,和塔顶到塔底的数字。
给出两种操作:
1. 将塔顶上的元素单独移动到一个新的塔 +1
2.将整个塔的元素移动到另一塔上 -1
求最小操作数量使得成为一个递增塔。

思路:存储最终状态和每个值的位置。枚举一下位置之下的位置是否是当前的后一个元素。或者前一个元素根本大于后一个元素。这样1操作和2操作都要增加。然后就是有多少塔2操作多少次,然后减1就ok。采用s[pos[num]+1] 来访问到某个元素的位置的下一个位置。非常好的思路。

code:

int n;
	cin>>n;
	int m;
	int he=0,fen=0,cnt=0;
	for(int i=1;i<=n;i++){
		cin>>m;
		int x;
		for(int j=1;j<=m;j++){
			cin>>x;
			ve[i].push_back(x);
			s[++cnt] = x;
		}
	}
	sort(s+1,s+cnt+1);
	for(int i=1;i<=cnt;i++)
		mp[s[i]] = i;
	for(int i=1;i<=n;i++){
		he++;
		for(int j=0;j<ve[i].size()-1;j++){
			if(s[mp[ve[i][j]]+1]!=ve[i][j+1]||ve[i][j]>ve[i][j+1]){
				fen++;
				he++;
			}
		}
	}
	cout<<fen<<' '<<he-1<<endl;

C. Binary Strings are Fun:https://codeforces.ml/contest/1762/problem/C

大意是给出01字符串,如果由至少i个1或0扩展出来,那么就是好的。求所有前缀好的扩展数量。

分析:大概就是说你要求当前串从某个进行扩展,很明显的扩展规则当前状态和上个状态有关
例如01111,后面的1可以从前面进行多次扩展,这个扩展我们很容易想到是两倍状态。
但是01110,后面的0跟前面的0扩展无关,所以为1.自身扩展没有的状态。

思路:累计乘2相同的状态,如果遇到不一样的初始成1,对每次进行ans累加

code:

void solve()
{
	int n;
	cin>>n;
	for(int i=0;i<=n;i++) f[i] = 0;
	string s;
	cin>>s;
	int ans = 1;
	f[0]=1;
	for(int i=1;i<s.size();i++){
		if(s[i]==s[i-1]) f[i] = f[i-1]*2,f[i]%=mod9;
		else f[i] = 1;
		ans+=f[i];
		ans%=mod9;
	}
	cout<<ans<<endl;
}


C. Maximum Set:https://codeforces.ml/contest/1796/problem/C

大意是给出l和r,求出一个集合,是的集合内的任意两个元素x和y,存在x%y==0||y%x==0。求出集合元素数量最大值,以及为该值时的最大不同集合数量。

分析:数学推导问题。可以O(1)的复杂度解决这个问题。我们易求得集合元素数量的最大值。我们进一步可以求出存在多少个为最小递增量的数量。

同样,存在某些元素*3为该数量值。我们令最大值/2*3,然后减去左边界值。得出存在多少个数量,将这个数量*集合元素数量-1.因为总是存在在不同的元素点进行*3或*2操作,当然,这个操作贪心的想只会存在1次*3操作。故而得到推导式。

code:

void solve()
{
	int l,r;
	cin>>l>>r;
	if(l*2>r){
		cout<<1<<' '<<r-l+1<<endl;
		return;
	}
	int cnt = 1,p = 1;
	for(int i=l*2;i<=r;i*=2) cnt++,p*=2;
	int ans = (r/p)-(l-1)+max(0,(r/(p/2*3))-(l-1))*(cnt-1);
	cout<<cnt<<' '<<ans<<endl;
}