5.14测试
前言
今天测试,又被一众大佬摁在地上摩擦……只有150……
题目
1. 查询 (query)
题意:区间查询值为X的数的个数。
由于忘记了vector的二分,只好用分块来做,但是卡着时限……
#include<bits/stdc++.h>
using namespace std;
int n,q,l,r,x,a;
vector<int> pos[200005];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
pos[a].push_back(i);
}
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d",&l,&r,&x);
int p1=lower_bound(pos[x].begin(),pos[x].end(),l)-pos[x].begin();//第一个大等于的位置
int p2=upper_bound(pos[x].begin(),pos[x].end(),r)-pos[x].begin(); //第一个大于的位置
printf("%d\n",p2-p1);
}
return 0;
}
2.画画(paint)
题意:给一个矩形,每次选一种颜色填一个矩形,每种颜色只有一次。询问有多少种颜色可以是最开始涂的。
思路:把矩形压缩后处理,不然要超空间。处理出最小和最大的横纵坐标,遍历该矩形内,如有其他颜色就记录。注意跳开已经统计的颜色。
#include<bits/stdc++.h>
#define M 1000010
#define p(a, b) (a * mm + b - mm)
using namespace std;
int x_min[M],x_max[M],y_min[M],y_max[M],used[M],a[M],ans,n,m,K,fl,nxt[M],pre[M],vis[M],mm,u;
int find(int x){
if(!vis[x]) return x;
return nxt[x]=find(nxt[x]);
}
int main(){
fl=0;
cin>>n>>m>>K;
memset(x_min,0x3f,sizeof (x_min));
memset(y_min,0x3f,sizeof (y_min));
memset(x_max, 0, sizeof(x_max));
memset(y_max, 0, sizeof(y_max));
memset(used, 0, sizeof(used));
mm=max(n,m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
if(n > m) u = p(j, i);
else u = p(i, j);
scanf("%d", &a[u]);
}
if(n > m)swap(n, m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
u = p(i, j);
nxt[u] = p(i, j + 1);
pre[u] = p(i, j - 1);
if(x_max[a[u]] == 0 && a[u])fl++;
if(i < x_min[a[u]])x_min[a[u]] = i;
if(i > x_max[a[u]])x_max[a[u]] = i;
if(j < y_min[a[u]])y_min[a[u]] = j;
if(j > y_max[a[u]])y_max[a[u]] = j;
}
for(int i=1;i<=K;i++){
if(x_min[i]<=x_max[i]){
for(int j=x_min[i];j<=x_max[i];j++){
for(int k=y_min[i];k<=y_max[i];k=find(nxt[k])){
if(a[p(j, k)]!=i){
used[a[p(j, k)]]=1;
vis[p(j, k)]=1;
nxt[pre[p(j, k)]]=nxt[p(j ,k)];
pre[nxt[p(j, k)]]=pre[p(j, k)];
}
}
}
}
}
for(int i=1;i<=K;i++)
if(!used[i]) ans++;
if(ans==K&&fl==1&&ans>1) ans--;
if(fl) cout<<ans<<endl;
else cout<<0<<endl;
return 0;
}
3.数列(seq)
题意:
第一行三个整数\(𝑛, 𝑚, 𝑝\)表示数列长度\(𝑛\),询问个数\(𝑚\)和模数\(𝑝\)。
\(𝑚\)行,每行三个整数\(𝑙, 𝑟, 𝑘\),表示小B回答区间\([𝑙, 𝑟]\)中所有数的和对\(𝑝\)取模结果为\(𝑘\)。
输出最大的\(𝑋\),满足小B的前\(𝑋\)次回答中不存在矛盾。
思路:
\(S_i-S_j \equiv k (\mod p) \to S_i \equiv S_j+k (\mod p)\)
\(S_r-S_{l-1} \equiv k(\mod p)\)
所以,采用带权并查集,维护每个点到父亲的K值,每次加边并判断。
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
map<int,int>dad,h;
int n,m,l,r,X,Y,i,t,k,p;
char s1[110];
int find(int x){
if(!dad[x]) return x;
int t=find(dad[x]);
h[x]=(h[x]+h[dad[x]])%p;//累加边长
return dad[x]=t;
}
int main(){
cin>>n>>m>>p;
for(i=1;i<=m;i++){
cin>>l>>r>>k;
l--;
X=find(l);
Y=find(r);
t=(h[r]-h[l]+p)%p;//判重
if(X!=Y){//连边
dad[X]=Y;
h[X]=(t-k+p)%p;
}else if(t!=k) break;
}
cout<<i-1<<endl;
return 0;
}