0
点赞
收藏
分享

微信扫一扫

NOIP模拟19/07/06

​​WOJ4059 斐波那契​​

每次贪心选出最长的一段, 枚举45个斐波那契数, 如果存在 fib[i] - 当前数 出现, 就不合法

说一下我考场的做法

预处理每个数右边第一个与它组成斐波那契的位置 r[i]

NOIP模拟19/07/06_i++ 

可以单调队列优化

如何判断呢? 如果合法, 那么(j+1 -- i) 区间的最小的r[i] 应该大于i, 写个st表就可以了

#include<bits/stdc++.h>
#define N 100050
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt<<1) + (cnt<<3) + (ch-'0'), ch = getchar();
return cnt * f;
}
int n, a[N], tot, ans; ll fi[N];
int main(){
n = read();
for(int i=1; i<=n; i++) a[i] = read();
fi[1] = 1; fi[2] = 2;
for(int i=3; ;i++){
fi[i] = fi[i-1] + fi[i-2]; if(fi[i] > 2e9) break; tot = i;
}
for(int l = 1, r; l <= n; l = r){ set<int> S;
for(r = l; r <= n; r++){
int flag = 0; for(int i=1; i<=tot; i++)
if(S.count(fi[i] - a[r])){ flag = 1; break;}
if(flag) break; S.insert(a[r]);
} ans ++;
} printf("%d", ans);
return 0;
}

​​WOJ4060 序列​​

居然没有想到 ! 将 l1 -- r1 的限制转换成 1 -- l1-1, 和 1 -- r1 的

于是考虑如何求出中位数 <= k的方案数

想到了 middle 那道题, 将 <= k 的赋成 1, 否则 -1, 那么 1 的个数 >= -1 的个数就合法

求一个前缀和sum, 当前 i 就是查 i - Maxlen ---- i - Minlen 之间sum < sumi 的个数, 主席树就可以了

#include<bits/stdc++.h>
#define N 200050
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt<<1) + (cnt<<3) + (ch-'0'), ch = getchar();
return cnt * f;
}
const int S = 100000;
int n, a[N], m, sum[N], rt[N], tot;
struct Node{ int ls, rs, val;} t[N * 20];
void Build(int &x, int l, int r){
x = ++tot; if(l == r) return; int mid = (l+r) >> 1;
Build(t[x].ls, l, mid); Build(t[x].rs, mid+1, r);
}
void Insert(int &x, int last, int l, int r, int pos){
x = ++tot; t[x] = t[last]; t[x].val ++;
if(l == r) return; int mid = (l+r) >> 1;
if(pos <= mid) Insert(t[x].ls, t[last].ls, l, mid, pos);
else Insert(t[x].rs, t[last].rs, mid+1, r, pos);
}
int Quary(int a, int b, int l, int r, int L, int R){
if(!a) return 0; if(L<=l && r<=R) return t[a].val - t[b].val;
int mid = (l+r) >> 1, ans = 0;
if(L<=mid) ans += Quary(t[a].ls, t[b].ls, l, mid, L, R);
if(R>mid) ans += Quary(t[a].rs, t[b].rs, mid+1, r, L, R);
return ans;
}
ll Get(int A, int Minlen, int Maxlen){
for(int i=1; i<=tot; i++) t[i].ls = t[i].rs = t[i].val = 0;
memset(rt, 0, sizeof(rt)); tot = 0;
for(int i=1; i<=n; i++){
if(a[i] <= A) sum[i] = 1; else sum[i] = -1;
sum[i] += sum[i-1];
} Build(rt[0], 1, n + S); Insert(rt[0], rt[0], 1, n + S, 0 + S);
for(int i=1; i<=n; i++) Insert(rt[i], rt[i-1], 1, n + S, sum[i] + S);
ll ans = 0;
for(int i=1; i<=n; i++){
if(i - Minlen < 0) continue;
int r = i - Minlen, l = max(i - Maxlen, 0);
ans += (ll)Quary(rt[r], l ? rt[l-1] : 0, 1, n + S, 1, sum[i] + S);
} return ans;
}
int main(){
n = read();
for(int i=1; i<=n; i++) a[i] = read();
m = read();
while(m--){
int l1 = read(), r1 = read(), l2 = read(), r2 =read();
printf("%lld\n", Get(r1, l2, r2) - Get(l1-1, l2, r2));
} return 0;
}

​​WOJ4061栅栏​​

不能直接左下+1, 右上+1, 左上-1, 右下-1, 因为如果 i, j 分别在不同的矩阵就会炸

考虑将原问题转换, 相当于求是否存在一个矩阵, 使i在里面 但 j不在里面

有一个玄学做法, 就是给每个矩阵rand一个值val, 插入树状数组

如果 i 这个点的 val 的异或等于 j 的异或那么大概率i, j没有被隔开

#include<bits/stdc++.h>
#define N 2050
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt<<1) + (cnt<<3) + (ch-'0'), ch = getchar();
return cnt * f;
}
int Rand(){ return (rand() << 15) | rand();}
#define mp make_pair
#define pa pair<int, int>
int n, m, S, q, c[N][N];
map<pa, int> M;
void Add(int x, int y, int val){
for(int i=x; i<=S; i+=i&-i)
for(int j=y; j<=S; j+=j&-j)
c[i][j] ^= val;
}
int Ask(int x, int y){
int ans = 0;
for(int i=x; i; i-=i&-i)
for(int j=y; j; j-=j&-j)
ans ^= c[i][j];
return ans;
}
int main(){
n = read(), m = read(), q = read(); S = max(n, m) + 1;
while(q--){
int op = read(), x1 = read(), y1 = read(), x2 = read(), y2 = read();
if(op == 1){
int val = 0;
M[mp(x1 * S + y1, x2 * S + y2)] = val = Rand();
Add(x1, y1, val); Add(x2+1, y1, val); Add(x1, y2+1, val); Add(x2+1, y2+1, val);
}
if(op == 2){
int val = M[mp(x1 * S + y1, x2 * S + y2)];
Add(x1, y1, val); Add(x2+1, y1, val); Add(x1, y2+1, val); Add(x2+1, y2+1, val);
}
if(op == 3){
if(Ask(x2, y2) ^ Ask(x1, y1)) printf("No\n");
else printf("Yes\n");
}
} return 0;
}

 


举报

相关推荐

0 条评论