atcoder 杂题 #01
atcoder 杂题 #01
arc163_c
可能因为数学不好,所以栽在了这道 Luogu 评的绿题上。
题目大意:求一个长为
这题开始想着往通分后的
最终看了题解后知道,这道题要依靠这样一个式子不断拆解分数:
然后首先特判
然后考虑从 set
里,每次取出最小的数然后拆,这样才能使最终序列的分母尽可能小,注意到可能拆完后与原来序列中的数有重复,比如
由于重复的很少,所以最后一定能达成
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
第一次自己想出来黑题!纪念一下。
(其实感觉这道题的思维难度并没有黑题,代码也都是重复性的内容,并不难写)。
题目大意:给定
首先,套路地,把曼哈顿距离转化为切比雪夫距离,把
实际上就是考虑到一个点曼哈顿距离相等的点,形成了一个倾斜
切比雪夫距离就是对于两个点
回到题目上来,我们每次
我们只关心这个无序对的第二个点
然后我们能求出所有能出现在最终点对中的点,再对这些点统计答案。
这个问题可以 BFS 做,具体地,对每个 set
维护当前还没有遍历到的
我们每次对 set
,二分位置取出
每当一个点加入队列时,就把它对应 set
中的点删掉,这样就能保证每个遍历到的点都是新的点,保证了复杂度。
每个点在 set
中遍历
求出所有能遍历到的点后,距离其中一个点为
再用类似方法求出个数即可。把点扔到 vector
里。二分位置,两个位置相减求个数。注意正方形的四个角可能算重。
最后由于是无序对,答案需要除以 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
首先考虑二分答案,然后在时间
考虑把攻击方式按
那么对于
而对于
在每个段,我们可以
具体地,就是解
细节:我们可以插入一个 __int128
。
时间复杂度
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 计数,又由于
然后考虑怎么限制,我们直接猜结论。
以 0 为例,如果我们要填第
我们可以依次对每个
可以感性地感受到这个结论应该是正确的。
打完后,发现样例过了,验证了我们的猜想是正确的。
时间复杂度
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】