Codeforces Round #673 (Div. 1) 补题

A k-Amazing Numbers

水题

#include<bits/stdc++.h>
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ll long long
using namespace std;
const int maxn=3e5+5;
int a[maxn],Start[maxn],l[maxn],ans[maxn],ANS[maxn];
int main()
{
	io_opt;
	int T,n;
	cin>>T;
	for(int id=1;id<=T;id++){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];ANS[i]=0;
			if(Start[a[i]]!=id){
				ans[a[i]]=i;
				l[a[i]]=i;
				Start[a[i]]=id;
			}
			else{
				ans[a[i]]=max(ans[a[i]],i-l[a[i]]);
				l[a[i]]=i;
			}
		}
		for(int i=1;i<=n;i++){
			if(Start[i]==id){
				ans[i]=max(ans[i],n+1-l[i]);
				if(ANS[ans[i]]==0){
					ANS[ans[i]]=i;
				}
			}
		}
		int M=0x3f3f3f3f,S=0;
		for(int i=1;i<=n;i++){
			if(ANS[i]==0){
				if(S==0) cout<<"-1 ";
				else{
					cout<<M<<' ';
				}
			}
			else{
				S=1;
				M=min(M,ANS[i]);
				cout<<M<<' ';
			}
		}
		cout<<endl;
	}
}

B Make Them Equal

非常非常有趣的题,简单思考易知,把从2到n的数字尽量全部转移到1上,再由1往2到n上补充数是最优解,只需要2n次,但可能会有情况,比如 a 99 = 98 a_{99}=98 a99=98时这里面的98就取不出来,需要1先给他一部分,让他达到取出的最低限度,然后取出,再由1还回去,这就是3步,但这样仍然WA了。
接下来的调试过程就只能说是小技巧了,比如1先给缺口小的单位补充数,用优先队列对于缺口进行排序等等,调着调着莫名其妙就A了,但仍然感觉不太对劲,比赛中我代码一定被Hack(笑)

#include<bits/stdc++.h>
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ll long long
using namespace std;
const int maxn=4e4+5;
int Start[maxn],l[maxn],ans[maxn],ANS[maxn],lu[5][maxn],CNT;
ll a[maxn];
struct E
{
	int id,spare;
};
bool operator <(E x,E y)
{
	if(x.spare==y.spare){
		return x.id<y.id;
	}
	else return x.spare>y.spare;
}
priority_queue<E> P;
void insert(int x1,int x2,int v1)
{
	++CNT;
	lu[1][CNT]=x1;lu[2][CNT]=x2;lu[3][CNT]=v1;
}
int main()
{
	io_opt;
	int T,n;
	cin>>T;
	while(T--){
		cin>>n;CNT=0;
		ll tot=0;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			tot+=a[i];
		}
		if(tot%n!=0){
			cout<<"-1"<<endl;
			continue;
		}
		tot=tot/n;
		for(int i=2;i<=n;i++){
			int m=a[i]/i;
			ll Q=1ll*m*i;
			if(Q!=0){
				if(a[i]-Q==0){
					a[i]-=Q;a[1]+=Q;
					insert(i,1,m);
				}
				else{
					if(a[1]>=i-(a[i]-Q)){
						insert(1,i,i-(a[i]-Q));
						insert(i,1,m+1);
						a[1]+=a[i];a[i]=0;
					}
					else{
						a[i]-=Q;a[1]+=Q;
						insert(i,1,m);
					}
				}
			}
			if(a[i]>0){
				E CN;
				CN.id=i;CN.spare=i-a[i];
				P.push(CN);
			}
		}
		int flag=1;
		while(!P.empty()){
			E CN=P.top();P.pop();
			ll X_1=CN.id;
			ll res=X_1-a[X_1];
			if(a[1]<res){
				flag=0;
				break;
			}
			a[1]-=res;a[X_1]+=res;
			insert(1,X_1,res);
			a[1]+=X_1;a[X_1]-=X_1;
			insert(X_1,1,1);
		}
		if(flag==0){
			cout<<"-1"<<endl;
			continue;
		}
		for(int i=2;i<=n;i++){
			int X_1=tot-a[i];
			a[1]-=X_1;a[i]+=X_1;
			insert(1,i,X_1);
		}
		if(CNT>3*n){
			cout<<"-1"<<endl;
			continue;
		}
		else{
			cout<<CNT<<endl;
			for(int i=1;i<=CNT;i++){
				cout<<lu[1][i]<<' '<<lu[2][i]<<' '<<lu[3][i]<<endl;
			}
		}
	}
}

C. XOR Inverse

01字典树

构造01字典树,构造过程的每个节点记录01对(这一位为0的数字在前面,而后面的数字这一位是1则构成01对),和10对的数量,最后根据每一层的01对和10对的数量比较来选择这一位是0还是1

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int tol; //�ڵ���� 
const int MAXN=3e5;
int ch[32*MAXN][2]; //�ߵ�ֵ 
int siz[2][32*MAXN],ans[40];
ll a01[40],a10[40];
void init()
{
    tol=1;
    ch[0][0]=ch[0][1]=0;
}
void insert(ll x)
{
    int u=0;
    for(int i=32;i>=0;i--)
    {
        int v=(x>>i)&1;
        //cout<<x<<' '<<i<<' '<<v<<' '<<u<<endl;
        if(v==1){
        	a01[i]+=siz[0][u];
        	siz[1][u]++;
		}
        else{
        	a10[i]+=siz[1][u];
        	siz[0][u]++;
		}
		/*if(i==0){
			cout<<x<<' '<<a01[i]<<' '<<a10[i]<<endl;
		}*/
        if(!ch[u][v])
        {
            ch[tol][0]=ch[tol][1]=0; 
            ch[u][v]=tol++;
        }
        u=ch[u][v];
    }
}
int main()
{
	int n;
	scanf("%d",&n);
	init();
	for(int i=1;i<=n;i++){
		ll cnt;
		scanf("%lld",&cnt);
		insert(cnt);
	}
	ll ans=0,num_inver=0;
	for(int i=32;i>=0;i--){
		//cout<<i<<' '<<a01[i]<<' '<<a10[i]<<endl;
		if(a01[i]>=a10[i]){
			ans=1ll*ans*2;
			ans+=1ll*0;
			num_inver+=1ll*a10[i];
		}
		else{
			ans=1ll*ans*2;
			ans+=1ll*1;
			num_inver+=1ll*a01[i];
		}
	}
	printf("%lld %lld\n",num_inver,ans);
}

D. Graph and Queries

反向建图

dfs序+并查集+线段树+反向建树

用的都是简单的算法,合起来却很有难度,网上都说是图上的经典问题,我却完全没有印象,看来做题还是少了
因为在询问过程中伴随着删边操作,并查集合并非常简单但删边操作很难复现在并查集上,所以采用反向并查集,反向建图,离线询问的方法将删边操作改为加边操作,最后通过dfs序和线段树的方法维护子树最大值,并支持单点修改和区间询问
这道题我也非常喜欢,运用一点数据结构但也不是阴间的数据结构,通过思维将传统数据结构进行组合求解,既有成就感又有思维的乐趣

E. Split

F. Showing Off

待补充

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值