24.12.8

CF Round887 Div2 题目思路与代码

星期一:

补cf round887 div2 C                                                    cf传送门

据说是和昆明场的题有相似之处

思路:考虑倒着推,先找出k天之后的第一个数在k-1天排哪

其实要找的就是此数目前在第pos个位置,那么要还原到上一天,它之前应插入多少数(记x个),还原到上一天后此数的位置就变成了pos+x

例如 a=1,2,5,那么第k天的第一个就是第k-1天的第3个,k-2天的第5个,k-3天的第8个

a=1,2,5,那么前一天的第1,2个数应插在第1个数前,第5个数应插在第3个数前

对a做一些合乎直觉的处理(-i+1),变为1,1,3,发现只要对于pos找出有多少ai<=pos,即pos前应插入多少个数,二分实现即可

代码如下:

const int N=5e5+10,M=1e4+10;
const int INF=0x3f3f3f3f;
const int mod=998244353;
ll n;
ll a[N];
void solve(){
	ll k; cin >> n >> k;
	for(int i=1;i<=n;i++){
		cin >> a[i];
		a[i]+=-i+1;
	}
	if(a[1]!=1){cout << "1\n"; return ;}
	ll pos=1;
	while(k--){
		int idx=upper_bound(a+1,a+n+1,pos)-a-1;
		pos+=idx;
	}
	cout << pos << "\n";
}

星期二:

cf round887 div2 D 构造                                                     cf传送门

乱搞搞过去的,这里说下怎么写的,正解可以看官方

思路:首先可注意到ai相对大小即bi相对大小,对a排个序

ai的值意义即与前ai个数相加大于0,可以做个差分,然后判断每个数有多少个与其和大于0,若值不等于ai,即无解

然后神秘面向样例构造,若和自己相加>0,则赋个正数,否则和最后一个相加为正的数和为1

代码如下:

const int N=5e5+10,M=1e4+10;
const int INF=0x3f3f3f3f;
const int mod=998244353;
ll n;
struct nod{
	int fi,se;
	int ans;
}a[N];
//PII a[N];
//int ans[N];
int cf[N];
void solve(){
	cf[0]=0;
	cin >> n;
	for(int i=1;i<=n;i++){
		cf[i]=0;
		cin >> a[i].fi;
		a[i].se=i;
	}
	sort(a+1,a+n+1,[](nod b,nod c){
		return b.fi>c.fi;
	});
	for(int i=1;i<=n;i++)
		if(a[i].fi) cf[0]++,cf[a[i].fi+1]--;
	for(int i=1;i<=n;i++){
		cf[i]+=cf[i-1];
//		cout << cf[i] << " \n"[i==n];
		if(cf[i]!=a[i].fi){cout << "NO\n"; return ;}
	}
	a[0].ans=n+1;
	for(int i=1;i<=n;i++){
		if(cf[i]>=i) a[i].ans=cf[i]-i+1;
		else a[i].ans=1-a[cf[i]].ans;
	}
	sort(a+1,a+n+1,[](nod b,nod c){
		return b.se<c.se;
	});
	cout << "YES\n";
	for(int i=1;i<=n;i++)
		cout << a[i].ans << " \n"[i==n];
}

星期五:

补cf round887 div2 E 反悔贪心                                              cf传送门

思路:不是很明白,建议看官方题解

代码如下:

const int N=1e6+10,M=1e4+10;
const int INF=0x3f3f3f3f;
const int mod=998244353;
ll n;

void solve(){
	ll k; cin >> n >> k;
	ll lst=0,ans=0;
	priority_queue<ll,vector<ll>,greater<>>pq;
	for(int i=1;i<=n;i++){
		ll a; cin >> a;
		if(a==k) a=0;
		if(a>lst){
			pq.push(a-lst);
			ans+=pq.top(); pq.pop();
		}else pq.push(k+a-lst);
		lst=a;
	}
	cout << ans << "\n";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值