atcoder 杂题 #01

atcoder 杂题 #01

arc163_c

可能因为数学不好,所以栽在了这道 Luogu 评的绿题上。

题目大意:求一个长为 n 的正整数序列 a 使得 1ai=1,要求 ai 互不相同,且 ai109

这题开始想着往通分后的 lcmn 个因数的和等于 lcm 方向考虑,发现并没有什么有趣的性质。

最终看了题解后知道,这道题要依靠这样一个式子不断拆解分数:

1x=1x+1+1x(x+1)

然后首先特判 n2 的情况,n=1 就是 a1=1n=2 就是无解。

然后考虑从 12,13,16 开始拆,把这些东西加入一个 set 里,每次取出最小的数然后拆,这样才能使最终序列的分母尽可能小,注意到可能拆完后与原来序列中的数有重复,比如 12=13+16,所以如果有重复就直接把它加入 a 数组里,以后不再拆它。

由于重复的很少,所以最后一定能达成 n 个,我们也可写完后验证可不可行。

AC 代码:

int T,n;
set<int> s;
const int N=1005;
int a[N];
signed main(){
cin>>T;
while(T--){
cin>>n;
if(n==1){
cout<<"Yes\n1\n";
continue;
}
if(n==2){
cout<<"No\n";
continue;
}
s={2,3,6};
int tot=0;
while(tot+s.size()<n){
int x=*s.begin();
if(s.find(x+1)!=s.end()||s.find((ll)(x+1)*x)!=s.end())a[++tot]=x,s.erase(s.begin());
else{
s.erase(s.begin());
s.insert(x+1);
s.insert((ll)x*(x+1));
}
}
cout<<"Yes\n";
fo(i,1,tot)cout<<a[i]<<" ";
for(auto i:s)cout<<i<<" ";
}
return 0;
}

arc065_c

第一次自己想出来黑题!纪念一下。
(其实感觉这道题的思维难度并没有黑题,代码也都是重复性的内容,并不难写)。

题目大意:给定 n 个点,和初始无序点对 (a,b),记 dis(a,b) 表示点 a,b 的曼哈顿距离,可以不断操作,每次操作可以从一个无序点对 (a,b) 移动到另一个满足 dis(a,c)=dis(a,b) 的无序点对 (a,c) 问你最终能到达多少个无序点对。

首先,套路地,把曼哈顿距离转化为切比雪夫距离,把 (x,y)(x+y,xy)
实际上就是考虑到一个点曼哈顿距离相等的点,形成了一个倾斜 45 度的正方形。把正方形转正,就从原来坐标系下的 (x,y) 变成了新坐标系下的 (x+y,xy),曼哈顿就变成了切比雪夫距离。

切比雪夫距离就是对于两个点 (x,y),(x,y),距离为 max(|xx|,|yy|)

回到题目上来,我们每次 (a,b)(a,c) 实际上可以看作 (b,a)(a,c)
我们只关心这个无序对的第二个点 a,然后每次移动就是把无序对的第二个点换成满足 dis(a,b)=LbL 为初始点对的距离。

然后我们能求出所有能出现在最终点对中的点,再对这些点统计答案。

这个问题可以 BFS 做,具体地,对每个 xset 维护当前还没有遍历到的 x=x 的点及其 y, 对每个 y 也这样。
我们每次对 x=xuLset,二分位置取出 yuLyyu+L 的点,然后把这些点加入队列,对于 x=xu+L,y=yuL,y=yu+L 的也类似。

每当一个点加入队列时,就把它对应 set 中的点删掉,这样就能保证每个遍历到的点都是新的点,保证了复杂度。
每个点在 set 中遍历 O(1) 次,且加入队列更新其他点 1 次,所以这一部分的复杂度是 O(nlogn) 的。

求出所有能遍历到的点后,距离其中一个点为 L 的点与这个点都能形成合法点对。
再用类似方法求出个数即可。把点扔到 xyvector 里。二分位置,两个位置相减求个数。注意正方形的四个角可能算重。

最后由于是无序对,答案需要除以 2。

AC 代码,AC 记录

const int N=1e5+5;
int n,t1,t2;
int X[N],Y[N];
int qx[N],qy[N];
int bx[N],by[N];
int bz[N];
set<pair<int,int> > x1[N],y1[N];
vector<int> x2[N],y2[N];
signed main(){
read(n,t1,t2);
fo(i,1,n){
int x,y; read(x,y);
X[i]=x+y,Y[i]=x-y;
bx[i]=X[i],by[i]=Y[i];
}
sort(bx+1,bx+1+n);
sort(by+1,by+1+n);
int len=unique(bx+1,bx+1+n)-bx-1;
fo(i,1,n)qx[i]=lower_bound(bx+1,bx+1+len,X[i])-bx;
int lx=len;
len=unique(by+1,by+1+n)-by-1;
fo(i,1,n)qy[i]=lower_bound(by+1,by+1+len,Y[i])-by;
fo(i,1,n)x1[qx[i]].insert({Y[i],i}),y1[qy[i]].insert({X[i],i});
queue<int> q;
q.push(t1),bz[t1]=1;
x1[qx[t1]].erase({Y[t1],t1}),y1[qy[t1]].erase({X[t1],t1});
q.push(t2),bz[t2]=1;
x1[qx[t2]].erase({Y[t2],t2}),y1[qy[t2]].erase({X[t2],t2});
int L=max(abs(X[t1]-X[t2]),abs(Y[t1]-Y[t2]));
while(q.size()){
int u=q.front(); q.pop();
int l=lower_bound(bx+1,bx+1+lx,X[u]-L)-bx;
vector<int> add;
if(bx[l]==X[u]-L){
auto p1=x1[l].lower_bound({Y[u]-L,0}),p2=x1[l].lower_bound({Y[u]+L+1,0});
while(p1!=p2){
add.push_back(p1->second);
++p1;
}
}
l=lower_bound(bx+1,bx+1+lx,X[u]+L)-bx;
if(bx[l]==X[u]+L){
auto p1=x1[l].lower_bound({Y[u]-L,0}),p2=x1[l].lower_bound({Y[u]+L+1,0});
while(p1!=p2){
add.push_back(p1->second);
++p1;
}
}
l=lower_bound(by+1,by+1+len,Y[u]-L)-by;
if(by[l]==Y[u]-L){
auto p1=y1[l].lower_bound({X[u]-L,0}),p2=y1[l].lower_bound({X[u]+L+1,0});
while(p1!=p2){
add.push_back(p1->second);
++p1;
}
}
l=lower_bound(by+1,by+1+len,Y[u]+L)-by;
if(by[l]==Y[u]+L){
auto p1=y1[l].lower_bound({X[u]-L,0}),p2=y1[l].lower_bound({X[u]+L+1,0});
while(p1!=p2){
add.push_back(p1->second);
++p1;
}
}
sort(add.begin(),add.end());
add.resize(unique(add.begin(),add.end())-add.begin());
for(auto i:add){
bz[i]=1;
q.push(i);
x1[qx[i]].erase({Y[i],i}),y1[qy[i]].erase({X[i],i});
}
}
fo(i,1,lx)x1[i].clear();
fo(i,1,len)y1[i].clear();
fo(i,1,n)x1[qx[i]].insert({Y[i],i}),y1[qy[i]].insert({X[i],i});
fo(i,1,lx)for(auto j:x1[i])x2[i].push_back(j.first);
fo(i,1,len)for(auto j:y1[i])y2[i].push_back(j.first);
ll ans=0;
fo(i,1,n){
if(bz[i]){
int l=lower_bound(bx+1,bx+1+lx,X[i]-L)-bx;
if(bx[l]==X[i]-L)ans+=upper_bound(x2[l].begin(),x2[l].end(),Y[i]+L-1)-lower_bound(x2[l].begin(),x2[l].end(),Y[i]-L);
l=lower_bound(bx+1,bx+1+lx,X[i]+L)-bx;
if(bx[l]==X[i]+L)ans+=upper_bound(x2[l].begin(),x2[l].end(),Y[i]+L)-lower_bound(x2[l].begin(),x2[l].end(),Y[i]-L+1);
l=lower_bound(by+1,by+1+len,Y[i]-L)-by;
if(by[l]==Y[i]-L)ans+=upper_bound(y2[l].begin(),y2[l].end(),X[i]+L)-lower_bound(y2[l].begin(),y2[l].end(),X[i]-L+1);
l=lower_bound(by+1,by+1+len,Y[i]+L)-by;
if(by[l]==Y[i]+L)ans+=upper_bound(y2[l].begin(),y2[l].end(),X[i]+L-1)-lower_bound(y2[l].begin(),y2[l].end(),X[i]-L);
}
}
write(ans/2);
return 0;
}

abc303_f

首先考虑二分答案,然后在时间 ji 方式攻击的贡献就确定了,我们要判断以最优方式攻击的贡献和是否不小于 H

考虑把攻击方式按 ti 排序,我们依次确定时间为 titi+1 这一段以最优方式攻击的贡献和。

那么对于 ji 的攻击方式,一个时间的贡献就是 max{tj×dj}
而对于 j>i 的攻击方式,时间 k 的贡献就是 k×max{dj}

在每个段,我们可以 O(1) 计算一个分界点,分界点前以 ji 的作为攻击方式更优,分界点后以 j>i 的作为攻击方式更优。
具体地,就是解

x×maxj>i{dj}>maxji{tj×dj}

细节:我们可以插入一个 t=1,d=0 的攻击方式,可以方便实现。check 时需要注意特判 mid 的边界,同时记得开 __int128

时间复杂度 O(nlogV)

AC 代码:

const int N=3e5+5;
ll h;
int n;
pair<int,int> a[N];
int mx[N];
int check(ll x){
it128 sum=0;
ll Max=0;
fo(i,1,n){
Max=max(Max,(ll)a[i].first*a[i].second);
if(a[i].first>x)break;
if(a[i].first!=a[i+1].first){
if(i==n)sum+=(it128)(x-a[i].first+1)*Max;
else {
ll t=floor((ld)Max/mx[i+1]);
if(t<a[i].first)t=a[i].first-1;
if(t>=a[i+1].first)t=a[i+1].first-1;
if(t>=x){
sum+=(it128)(x-a[i].first+1)*Max;
break;
}
sum+=(it128)(t-a[i].first+1)*Max;
int up=a[i+1].first;
if(up>x)up=x+1;
sum+=(it128)(t+up)*(up-t-1)/2*mx[i+1];
}
}
}
return sum>=h;
}
signed main(){
read(n,h);
fo(i,1,n)read(a[i].first,a[i].second);
++n;
a[n]={1,0};
sort(a+1,a+1+n);
fd(i,n,1)mx[i]=max(mx[i+1],a[i].second);
ll l=1,r=1e18,ans=0;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
write(ans);
return 0;
}

arc065_d

不知道怎么回事,十分钟内秒掉了,感觉难度评高了(洛谷上评紫,kenkoooo 上评了橙色)。

这道题首先直接对每个位置填 0 或 1 计数,又由于 n3000 所以考虑设 fi,j 表示前 i 个填了 j 个 0 的方案数。

然后考虑怎么限制,我们直接猜结论。
以 0 为例,如果我们要填第 j 个 0,那么就要满足前 i 个位置在 0 尽量多的情况下的 0 的个数要不小于 j
我们可以依次对每个 [l,r] 的区间排序,就能把 0 尽可能往前放。

可以感性地感受到这个结论应该是正确的。

打完后,发现样例过了,验证了我们的猜想是正确的。

时间复杂度 O(nmlogn)

AC 代码也非常短:

const int N=3005;
char s[N],t[N];
int n,m;
int l[N],r[N];
int a[N],b[N];
int f[N][N];
const int mod=1e9+7;
signed main(){
read(n,m),read(s+1);
fo(i,1,m){
read(l[i],r[i]);
}
fo(i,1,n)t[i]=s[i];
fo(i,1,m){
sort(s+l[i],s+r[i]+1);
sort(t+l[i],t+r[i]+1,greater<>());
}
fo(i,1,n){
a[i]=a[i-1],b[i]=b[i-1];
a[i]+=s[i]=='0';
b[i]+=t[i]=='1';
}
f[0][0]=1;
fo(i,1,n){
fo(j,0,i){
if(j>0)(f[i][j]+=f[i-1][j-1]*(a[i]>=j))%=mod;
(f[i][j]+=(f[i-1][j]*(b[i]>=i-j)))%=mod;
}
}
int ans=0;
fo(i,0,n)(ans+=f[n][i])%=mod;
write(ans);
return 0;
}
posted @   dengchengyu  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示