You had me at hello.|

_Youngxy

园龄:3年7个月粉丝:5关注:28

构造杂题(ing)

「CF388B」Fox and Minimal path

构造一个图,使得第i层下方的点的路径数为2i,然后构造一条主链,通过二进制拆分,将对应位置与主链项链即可

void solve(){
	add(1,++idx);
	add(1,++idx);
	for(int i=1;i<l;i++){
		idx++;
		add(idx-1,idx);
		add(idx-2,idx);
		idx++;
		add(idx-2,idx);
		add(idx-3,idx); 
	}
	add(++idx,1); 
	for(int i=1;i<l;i++){
		idx++; 
		add(idx-1,idx); 
	}
	add(idx,2);
	for(int i=1;i<=l;i++){
		if(a[i]){//二进制倒数第i位
			if(2*(l+1)+i+1>idx) add((i+1)*2,2);
			else add((i+1)*2,2*(l+1)+i+1);
		}
	}
}

「CF1305D」Kuroni and the Celebration

询问叶子节点的lca,如若是ta们两个之一,那么ta(lca)为根

若不是,将xlcalcay这两条链上的点(处理)从set弹出(ta们不可能为根)

然后将lca加入下一轮的set中

重复此操作,直到set里只剩1个元素,ta即为根

void dfs(int u,int fa,int x){
	now.erase(u);
	if(u==x) return;
	for(int v:G[u]) {
		if(v!=fa) dfs(v,u,x);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
		d[u]++;d[v]++;
	}
	for(int i=1;i<=n;i++) {
		if(d[i]==1) now.insert(i);
	}
	while(now.size()>1){
		nxt.clear();
		while(1){
			if(now.size()==1) {
				nxt.insert(*now.begin());
				break;
			}else if(now.empty()) break;
			int x=*now.begin();
			now.erase(now.begin());
			int y=*now.begin();
			now.erase(now.begin());
			int lca;
			printf("? %d %d\n",x,y);
			fflush(stdout);
			scanf("%d",&lca);
			dfs(x,0,lca);
			dfs(y,0,lca);
			nxt.insert(lca);
		}
		now=nxt;
	}
	printf("! %d\n",*now.begin());
	fflush(stdout);
	return 0;
}

「CF1686D」Linguistics

我们将字符串按照相邻字符是否相同划分为多个段

对于只有A/B的段就用单独的a/b就🆗了

主要是对于AB相间的段怎么处理:

首先,对于奇数段:AB,BA共用len/2

对于A开头的段:

  • 若只用AB,那么用的是c:(len/2)

  • 若不是,则AB,BA,共用(len/2)1

对于B开头的段:

  • 若只用BA,那么用的是c:(len/2)

  • 若不是,则AB,BA,共用(len/2)1

那么我们可以将这些段按照花费从小到大排序

然后若数量不够,则将sum加上w1,表示AB,BA共用w1

w=len/2,即花费

最后将c+d与sum比较,看c+d够不够即可

int main(){
	cin>>t;
	while(t--){
		scanf("%d%d%d%d",&a,&b,&ab,&ba);
		scanf("%s",s+1);
		len=strlen(s+1);
		cnta=0,cntb=0;
		for(int i=1;i<=len;i++){
			if(s[i]=='A') cnta++;
			else cntb++; 
		}
		if(cnta!=a+ab+ba||cntb!=b+ab+ba){
			printf("NO\n");
			continue;
		}
		sum=0;
		for(int i=1,j;i<=len;i=j+1){
			j=i;
			while(j<len&&s[j]!=s[j+1]) j++;
			if((j-i+1)%2==1) sum+=(j-i+1)/2;
			else{
				int w=(j-i+1)/2;
				if(s[i]=='A') x.push_back(w);
				else y.push_back(w);
			}
		}
		sort(x.begin(),x.end());
		sort(y.begin(),y.end());
		for(int i:x){
			if(ab>=i) ab-=i;
			else sum+=i-1;//i-1个ba 
		}
		for(int i:y){
			if(ba>=i) ba-=i;
			else sum+=i-1;//i-1个ab 
		}
		if(sum<ab+ba) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}

「CF1375E」 Inversion SwapSort

这个题就是我们先sort出我们的最终数组

然后将ta们的原id反排序回去(冒泡)

也就是倒着排回去,然后每次交换的时候记录下是交换的哪两个即可

这样就保证了每个逆序对只交换了一次

int main(){
    cin>>n;
    for (int i=1; i<=n; i++){
    	cin>>a[i].first;
		a[i].second=i;
    }
    sort(a+1,a+1+n);
    for (int i=1; i<=n; i++){
    	b[i]=a[i].second;
    }
    for (int i=1; i<=n; i++) {
    	for (int j=1; j<n; j++) {
    		if (b[j]>b[j+1]) {
                ans.push_back({b[j+1],b[j]});
                swap(b[j],b[j+1]);
            }
    	}
    }//冒泡排序
	cout<<ans.size()<<"\n";
	for(int i=0;i<(int)ans.size();i++){
		cout<<ans[i].first<<" "<<ans[i].second<<"\n";
	}
    return 0;
}

「CF1305E」 Kuroni and the Score Distribution

我们可以显然发现1,2,3,4,5,6,,n1,n这样的数列满足条件的三元组的个数增长是最快的,所以我们不妨从此入手

i个数的贡献为(i1)/2

我们可以一直列下去,直到k(满足条件的三元组的个数)>=m

此时我们应该考虑如何在现有基础上将k缩小为m

我们可以比较不是很显然地发现,n(最后一项的数值)每增加2,k就减少1,

因此我们可以通过增大后面的数的数值来缩小k

使k=m即可

由于有n的限制,我们将后面的数随便填一些大的数(ta们的间隔也要大),

那么这个题就做完了

int main(){
	scanf("%lld%lld",&n,&m);
	for (ll i=1;i<=n;i++){
		a[i]=i;
		czc+=(i-1)/2;
		if(czc>=m){
			a[i]+=2*(czc-m);
			ll add=1e9;
			for (ll j=n;j>i;j--){
				a[j]=(add-=(a[i]+1));
			} 
			fg=1;
			break;
		}
	}
	if(!fg) {
		printf("-1\n"); 
	}else{
		for(ll i=1;i<=n;i++){
			printf("%lld ",a[i]);
		}
	}
	return 0;
}

「CF487C」 Prefix Product Sequence

由于我们的(n1)!(就是n-1位置的前缀积)包含了n的所有因数(除了n),

所以(n1)! mod n必然为0,

但是如果n为质数肯定就不会出现这种情况(因为前面没有ta的因数(1不算))

所以n如果是合数的话,肯定就GG

这里有特殊情况:4

因为4=22

4也是可以的,所以需要特判一下

我们的1必须放在第一个,因为如果放1在中间的话,那当前位置与前一个的前缀积就是一样的,mod n的值自然一样,就GG了

我们的n必须放在最后一个,因为如果放n在中间的话,那当前位置及以后的前缀积mod n的值都为0,就GG了

考虑剩下的n-2个数

21,32,43,...,n1n2,nn1

这样的序列是完全没有问题的

因为第i项的前缀积为i

然后我们通过逆元可以将分数转换为整数就🆗了

int main(){
	pre();//质数
	scanf("%lld",&n);
	if(n==4||!p[n]){
		printf("YES\n");
		if(n==4){
			printf("1\n3\n2\n4\n");//特判
			return 0;
		}
	}else{
		printf("NO\n");
		return 0;
	}
	a[1]=1,a[n]=n;
	for(ll i=2;i<n;i++){
		a[i]=power(i-1,n-2)%n*i%n; 
	} 
	for(ll i=1;i<=n;i++){
		printf("%lld\n",a[i]);
	}
	return 0;
}

「GYM101611C」 Carpet

就是先走轻链,放在当前点的上一层

走重链的话,就放在这一层。。。。

没了

void dfs(ll x,ll fa){
	sz[x]=1;
	son[x]=-1;
	for(ll i=hd[x];i;i=nxt[i]){
		ll y=to[i];
		if(y==fa) continue;
		f[y]=x;
		dfs(y,x);
		sz[x]+=sz[y];
		if(son[x]==-1||sz[son[x]]<sz[y]) son[x]=y;
	}
}
void dfs1(ll x,ll yy){
	//cout<<"---"<<x<<" "<<yy<<"\n";
	X[x]=++c[yy],Y[x]=yy;
	if(son[x]==-1){
		return ;
	}
	for(ll i=hd[x];i;i=nxt[i]){
		ll y=to[i];
		if(y==f[x]||y==son[x]) continue;		
		dfs1(y,yy+1);
	} 
	dfs1(son[x],yy);
}

本文作者:_Youngxy

本文链接:https://www.cnblogs.com/yvette1217/p/16627760.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Youngxy  阅读(51)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示