Industrial Nuclear Water(计算几何)3星
题意:
给你两个点,问这两个点是否在所给三个面的同一侧
1000 ∣ x ∣ = y 2 + z 2 , 1000 ∣ y ∣ = x 2 + z 2 , 1000 ∣ z ∣ = x 2 + y 2 1000|x|=y^2+z^2,1000|y|=x^2+z^2,1000|z|=x^2+y^2 1000∣x∣=y2+z2,1000∣y∣=x2+z2,1000∣z∣=x2+y2
题解:
判断两点是否在一个面的同一侧,只需将点带入方程看结果是否符号一致
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1010;
int n,m;
ll a[5],b[5];
bool get(ll a,ll b,ll c){
return 1000*a<=b*b+c*c;
}
void solve(){
for(int i=0;i<3;i++) cin>>a[i];
for(int i=0;i<3;i++) cin>>b[i];
int f=1;
for(int i=0;i<3;i++){
if(get(a[(0+i)%3],a[(1+i)%3],a[(2+i)%3])!=get(b[(0+i)%3],b[(1+i)%3],b[(2+i)%3])){
f=0;
break;
}
if(get(-a[(0+i)%3],a[(1+i)%3],a[(2+i)%3])!=get(-b[(0+i)%3],b[(1+i)%3],b[(2+i)%3])){
f=0;
break;
}
}
if(f) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
An Easy Problem(思维+二分/堆)4星
题意:
求出 i ∗ j ( 1 ≤ i ≤ n , 1 ≤ j ≤ m ) i*j(1\leq i\leq n,1\leq j\leq m) i∗j(1≤i≤n,1≤j≤m)中的第 k k k大数
题解:
1)堆:
显然最大值一定在最后面的一列
将第 i i i行的最后一个元素插入堆中,每次取出其中的最大值,换为这一行的第二大值
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll,ll>PII;
const int N=1010;
ll n,m,k;
priority_queue<PII>q;
void solve(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++) q.push({i*m,i});
while(k--){
auto [x,y]=q.top();
q.pop();
q.push({x-y,y});
}
cout<<q.top().x;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}
2)二分:
转化为求第k小数,二分check对于每个 i i i小于等于 m i d mid mid的数的个数是否大于等于k
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll,ll>PII;
const int N=1010;
ll n,m,k;
bool check(ll mid){
ll res=0;
for(int i=1;i<=n;i++){
res+=min(m,mid/i);
}
return res>=k;
}
void solve(){
cin>>n>>m>>k;
k=n*m-k+1;
ll l=1,r=1e12,ans=r;
while(l<=r){
ll mid=l+r>>1;
if(check(mid)) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
cout<<ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}
Byfibonacci(DP)4星
题意:
T组询问,求出 w ( F ( x ) ) w(F(x)) w(F(x)),每一种用斐波那契数构成的x的方案的价值的和
方案的价值指涉及的每个斐波那契额数的乘积
题解:
每个数一定由小于等于本身的最大和次大斐波那契额数构成
f[i]=(f[i-g[pos]]*g[pos]+f[i-g[pos-1]]*g[pos-1])%mod;
次大值会被重复计算,所以当满足 次 大 值 ∗ 2 ≤ 当 前 值 次大值*2\leq 当前值 次大值∗2≤当前值时要减去重复计算的那一部分
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e7+10,mod=998244353;
int n,m;
ll f[N],g[110];
int vis[N],pos;
void init(){
g[2]=1,g[1]=1;
for(int i=3;;i++){
g[i]=g[i-1]+g[i-2];
if(g[i]>N) break;
m=i;vis[g[i]]=i;
}
f[0]=1,f[1]=2,f[2]=3;
for(int i=3;i<=1e7;i++){
if(vis[i]) pos=vis[i];
f[i]=(f[i-g[pos]]*g[pos]+f[i-g[pos-1]]*g[pos-1])%mod;
if(2*g[pos-1]<=i)//减去重复计算的一部分
f[i]=((f[i]-f[i-2*g[pos-1]]*g[pos-1]%mod*g[pos-1]%mod)%mod+mod)%mod;
}
}
void solve(){
cin>>n;
cout<<f[n]<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
init();
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
Kera’s line segment(区间转二维平面点+二维树状数组)4星
题意:
就是一个一维的数轴上面有一堆线段用一个三元组$(l , r , v a l ) $表示。
现在我们有两个操作:
- 就是往数轴上面添加线段
- 询问 [ L , R ] [ L , R ] [L,R] 这个区间里面线段权值最大跟最小的差值是多少??(只有被这个$[ L , R ] $区间完全覆盖才算在里面)
1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105
1 ≤ l , r ≤ 3000 1\leq l,r\leq 3000 1≤l,r≤3000
题解:
如何维护一个线段(区间)?
我们需要将每个区间映射成一个点,所以可以将区间 [ l , r ] [l,r] [l,r]转换为一个二维坐标 ( l , r ) (l,r) (l,r),查询区间 [ L , R ] [L,R] [L,R]就是查询左上角为 ( L , R ) (L,R) (L,R),右下角为 ( m a x l , m a x r ) (max_l,max_r) (maxl,maxr)的区间
为方便取前缀和,可以将区间 [ l , r ] [l,r] [l,r]转化为点 ( 3010 − l , r ) (3010-l,r) (3010−l,r),这样就可以用左上角为 ( 1 , 1 ) (1,1) (1,1),右下角为 ( 3010 − L , R ) (3010-L,R) (3010−L,R)的区域表示 [ L , R ] [L,R] [L,R]
前缀和用树状数组维护
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=3010;
int tr_ma[N][N],tr_mi[N][N];
int n,m;
inline int lowbit(int x){
return x&-x;
}
inline void add(int a,int b,int v){
int t=b;
while(a<N){
b=t;
while(b<N){
tr_ma[a][b]=max(tr_ma[a][b],v);
tr_mi[a][b]=min(tr_mi[a][b],v);
b+=lowbit(b);
}
a+=lowbit(a);
}
}
inline int query(int a,int b){
int t=b,ma=-1,mi=INF;
while(a){
b=t;
while(b){
ma=max(ma,tr_ma[a][b]);
mi=min(mi,tr_mi[a][b]);
b-=lowbit(b);
}
a-=lowbit(a);
}
return ma-mi;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(tr_mi,0x3f,sizeof tr_mi);
cin>>n>>m;
while(n--){
int a,b,v; cin>>a>>b>>v;
add(N-a,b,v);
}
int last=0;
while(m--){
int f,a,b,v; cin>>f;
if(f==1){
cin>>a>>b>>v;
a^=last,b^=last;
add(N-a,b,v);
}
else{
cin>>a>>b;
a^=last,b^=last;
last=query(N-a,b);
cout<<last<<endl;
}
}
return 0;
}
这篇博客探讨了计算几何在解决实际问题中的应用,包括判断两点是否位于三个平面上方的同一侧,以及通过二分查找和堆数据结构求解最大值。此外,还讨论了动态规划在斐波那契数列上的应用以及线段区间问题的二维平面解决方案,利用树状数组维护区间信息。

4559

被折叠的 条评论
为什么被折叠?



