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;
}