T1
题目大意:有 \(n\) 个点,到点 \(i\) 可以获得 \(A_i\) ,同时消耗 \(B_i\)
若当前价值小于 \(B_i\) 则不能到,问从 \(P\) 开始,任一点结束后的最大值。
最大值同时问最多访问点数。开始不用消耗
其实就是把所有 \(A_i\ge B_i\) 的点存下来,然后贪心
考试时脑抽忘记有消耗了。
T2
题意:一个平面上有两个圆心和 \(n\) 个点,每次给你两个圆的半径
问被任意一个圆覆盖的点的个数
考试时拼命想二分,然后憋一小时写了个 0 分
正解离线,知道后直接 WTF ,
设 \(d_1\) 为到点 \(A\) 的距离,\(d_2\) 为到点 \(B\) 的距离
询问按照 \(r_1\) 排序,点按照 \(d_1\) 排序
由于 \(r_1\) 递增,所以 \(r_{i+1}\) 和 \(r_i\) 有公共的答案,
可以均摊 \(O(1)\) 的时间求出点 \(A\) 包含的点,并把它们在树状数组中标记
于是 \(B\) 包含的不重复的点就是那些距离在 \(r_2\) 内且没被标记的点
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200005,M=200000;
int n,m,tmp,ans[N],t[N],dy[N],l,r,mid,res;
LL ax,ay,bx,by,r1,r2,d2[N],d1[N];
struct qry { LL r1,r2; int id; }q[N];
inline LL sqr(LL x) { return x*x; }
inline bool cmp(qry a,qry b) { return a.r1<b.r1; }
inline void add(int p,int v) { for(;p<=M;p+=p&-p)t[p]+=v; }
inline int ask(int p) { register int s=0; for(;p;p-=p&-p)s+=t[p]; return s; }
void sor(int l,int r) {
register int i=l,j=r;
register LL mid=d1[(l+r)>>1];
while(i<=j) {
while(d1[i]<mid)i++;
while(d1[j]>mid)j--;
if(i<=j) {
swap(d1[i],d1[j]);
swap(d2[i],d2[j]);
i++,j--;
}
}
if(i<r)sor(i,r);
if(j>l)sor(l,j);
}
int main() {
scanf("%d%d",&n,&m);
scanf("%lld%lld%lld%lld",&ax,&ay,&bx,&by);
for(int i=1,x,y;i<=n;i++) {
scanf("%d%d",&x,&y);
d1[i]=ceil(sqrt(sqr(x-ax)+sqr(y-ay)));
d2[i]=ceil(sqrt(sqr(x-bx)+sqr(y-by)));
add(d2[i],1);
}
sor(1,n);
for(int i=1;i<=m;i++) {
scanf("%lld%lld",&q[i].r1,&q[i].r2);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
for(int i=1,j=1;i<=m;i++) {
for(;d1[j]<=q[i].r1;j++)
add(d2[j],-1);
ans[q[i].id]=j-1+ask(q[i].r2);
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}
T3
题目大意:求 \(\sum_{i=m}^n i^k\) 模 \(p\) 意义下的值
对于 \(n-m\le 5000\) 的,直接暴力
然后剩下来的都是 \(k\le 2000\) 的数据
其实是恐怖如斯的自然数幂和,用第二类斯特林数
\(S_n^m=S_{n-1}^{m-1}+kS_{n-1}^m\)
定理:\(n^k=\sum_{i=0}^k S_k^i\times i!\times C_n^i\)
于是有
其中 \(\sum_{a=1}^n C_a^i=C_{n+1}^{i+1}\) 可以由 \(C_n^m=C_{n-1}^{m-1}+C_{n-1}^m\) 展开
由于在区间 \([n-i+1,n+1]\) 中有且只有一个 \(i+1\) 的倍数,循环时找出即可
复杂度 \(O(n^2)\)
#include<bits/stdc++.h>
using namespace std;
typedef long double LD;
typedef long long LL;
typedef unsigned long long uLL;
LL K,n,m,P,ans,tmp,s[2005][2005];
inline LL Mul(uLL x,uLL y) {
return (x*y-(LL)((LD)x/P*y)*P+P)%P;
}
inline LL Pow(LL x,LL y) {
register LL res=1;
for(;y;y>>=1,x=Mul(x,x))
if(y&1)res=Mul(res,x);
return res;
}
inline LL Ans(LL n) {
ans=0;
for(int i=1;i<=K;i++) {
tmp=s[K][i];
for(LL j=n-i+1;j<=n+1;j++) {
if(j%(i+1))tmp=Mul(tmp,j);
else tmp=Mul(tmp,j/(i+1));
}
ans=(ans+tmp)%P;
}
return ans;
}
int main() {
scanf("%lld%lld%lld%lld",&K,&n,&m,&P);
if(n-m<=5000) {
for(;m<=n;m++)(ans+=Pow(m,K))%=P;
return printf("%lld",ans),0;
}
s[0][0]=1;
for(int i=1;i<=K;i++)
for(int j=1;j<=K;j++)
s[i][j]=(s[i-1][j-1]+j*s[i-1][j]%P)%P;
printf("%lld",(Ans(n)-Ans(m-1)+P)%P);
}
T4
题意:给你 \(n\) 个点,每个点会一直想着它的目标点移动,设运动时间无限长
一个点如果跟上它的目标点,就会跟着目标点一起移动
问一组不知道往哪移动的点。一个点不知道的如何移动,当且仅当它的移动方向只决定于它自己的移动方向
前方高能
题目很复杂,其实就是让你找环!
为什么?
因为这是一个 \(n\) 个点 \(n\) 条边的图,至少有一个环
而这个环上的点在移动时距离不断减少,最终都不知道往哪移动
所以,坐标根本没用!
随便从一点出发,找到环即可
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int n,st,to[N],vis[N],ans[N];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&to[i]);
st=1;
while(!vis[st]) {
vis[st]=1;
st=to[st];
}
for(int i=to[st];i^st;i=to[i])
ans[++ans[0]]=i;
ans[++ans[0]]=st;
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++)
printf("%d ",ans[i]);
}
总结
T1:不要忘记条件
T2:在线难就离线
T3:自然数幂和
T4:阅读理解