星期一:
补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";
}