#离线 #广度优先搜索 #构造 #优先队列bfs
A
题意
- 求a/r上取整
思路
- 小技巧,求上取整
代码
void solve(){
int a,l,r;
cin >> a >> l >> r;
cout << (a+r-1)/r << endl;
}
B
题意
- 双排列序列,相同的两个数的最远距离
思路
- 开一个桶记录记录位置,同时更新答案
- 直接模拟
代码
void solve(){
int n;
cin >> n;
vector<int> a(n+10);
int ans=0;
for(int i=1;i<=2*n;i++){
int tmp;
cin >> tmp;
if(a[tmp]==0) a[tmp]=i;
else ans=max(ans,i-a[tmp]+1);
}
cout << ans << endl;
}
C
- 二分也好久没写了,发病了,二分的右界找错两次
题意
- 长为n的序列,按照如下规则攻击
- 初始攻击力为1
- 连续攻击攻击力+1,否则攻击力重置为1
- 要攻击多少次才能使得序列所有值均小于等于0
思路
- 攻击序列是等差数列
- 连续攻击一个元素是最优的
- 对于每一个元素二分攻击次数就行
代码
ll check(ll n){
ll l=1,r=(ll)sqrt(n*2)+1;
while(l<=r){
// if(n==22) cout << l << ' ' << r << endl;
ll mid=(r+l)/2;
if(mid*(mid+1)/2>=n){
r=mid-1;
}else{
l=mid+1;
}
}
// cout << l << endl;
return l;
}
void solve(){
int n;
cin >> n;
ll ans=0;
for(int i=1;i<=n;i++){
ll tmp;
cin >> tmp;
ans+=check(tmp);
}
cout << ans << endl;
}
D
题意
- 裸搜索,没啥好记录的
思路
- 纯白给
代码
vector<int> G[202020];
bool sb[202020];
int vis[202020];
vector<int> ans;
void dfs(int x,int fa){
vis[x]=1;
ans.push_back(x);
for(auto i:G[x]){
if(i==fa||sb[i]||vis[i]) continue;
dfs(i,x);
}
}
void solve(){
int n,m,x;
cin >> n >> m >> x;
for(int i=0;i<x;i++){
int tmp;
cin >> tmp;
sb[tmp]=1;
}
for(int i=0;i<m;i++){
int u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,-1);
sort(ans.begin(),ans.end());
for(auto i:ans){
cout << i << ' ' ;
}
cout << endl;
}
E
- 构造……奇偶判断
题意
- 一次攻击可以将相邻的两个元素-1,构造长为n的序列,使得序列元素的和为a,并且恰好k次最优攻击使得序列所有元素为0
思路
- 任何一次攻击可以使得a-1或者a-2
- 对于已知的k一定可以判断需要几次-1和-2,如果全部-1或-2都超出就直接寄了
- 然后判柱子
- 如果偶数柱子-2平铺,-1放最后一根
- 如果奇数柱子-2平铺前n-1根,-1放最后一根
- 如果平铺不够直接寄
- 最后n=1需要特判
代码
void solve(){
int n,a,k;
cin >> n >> a >> k;
vector<int> ans(n+10);
if(n==1) cout << (a==k?k:-1) << endl;
else if(a-k<0||2*k-a<0) cout << -1 << endl;
else{
if(n%2){
if((n-1)/2>a-k) cout << -1 << endl;
else{
int bas=2*(a-k)/(n-1);
int res=2*(a-k)%(n-1);
for(int i=1;i<=n&&res;i++){
ans[i]++;
res--;
}
for(int i=1;i<=n-1;i++) cout << ans[i]+bas << ' ';
cout << 2*k-a << endl;
}
}else{
if(n/2>a-k) cout << -1 << endl;
else{
int bas=2*(a-k)/n;
int res=2*(a-k)%n;
for(int i=1;i<=n&&res;i++){
ans[i]++;
res--;
}
for(int i=1;i<=n;i++) cout << ans[i]+bas+(i==n?2*k-a:0) << ' ';
cout << endl;
}
}
}
}
F
题意
- n*m地图,每个点有自己的val
- 在第一行撒伤害为x毒,毒会干掉小于自己的值并向四个方向传播
- 一共q次询问,每次给出初始毒x
思路一
- 观察发现,随着x增大,只会增加一些点被抬走
- 把所有询问存下来,按升序排序
- 然后做一个按血量的优先队列bfs
- 入队是无条件的
代码一
struct ty{
int x,y,val;
bool operator<(const ty &a) const {
return val>a.val;
}
};
vector<ty> mp;
vector<pii> qr;
bool vis[550][550];
int a[550][550];
int ans[202020];
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void solve(){
int n,m,q;
cin>> n >> m >> q;
priority_queue<ty> pq;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ty tmp;
cin >> a[i][j];
tmp.x=i,tmp.y=j,tmp.val=a[i][j];
mp.push_back(tmp);
if(i==1) pq.push(tmp);
}
}
for(int i=1;i<=q;i++){
ll x;
cin>>x;
qr.push_back({x,i});
}
sort(qr.begin(),qr.end());
ll sum=0;
for(auto [x,id]:qr){
while(!pq.empty()&&pq.top().val<=x){
int X=pq.top().x;
int Y=pq.top().y;
int v=pq.top().val;
pq.pop();
if(vis[X][Y]) continue;
vis[X][Y]=1;
sum++;
for(int i=0;i<4;i++){
int tx=X+dir[i][0];
int ty=Y+dir[i][1];
if(tx<1||ty<1||tx>n||ty>m||vis[tx][ty]) continue;
pq.push({tx,ty,a[tx][ty]});
}
}
ans[id]=sum;
}
for(int i=1;i<=q;i++) cout << ans[i] << endl;
}
思路二
- 硬搞
- 依然离线,同时把所有点也升序排序
- 然后把所有点依次加入,维护并查集,记录被覆盖的点数
- 同时并查集维护每个集合的size和是否和第一行联通
代码二
ll ans;
vector<pii> mp;
vector<pii> qr;
int fa[550*550];
int siz[550*550];
bool top[550*550];
bool vis[550*550];
int res[202020];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
void merge(int x,int y){
int rx=find(x),ry=find(y);
if(rx==ry) return;
if(siz[rx]>siz[ry]) swap(rx,ry);
fa[rx]=ry;
if(top[rx]&&!top[ry]) ans+=siz[ry];
if(top[ry]&&!top[rx]) ans+=siz[rx];
siz[ry]+=siz[rx];
top[ry]=top[ry]||top[rx];
}
void solve(){
int n,m,q;
cin>> n >> m >> q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int id=i*(m+1)+j;
fa[id]=id;
siz[id]=1;
top[id]=(i==1);
ll val;
cin>>val;
mp.push_back({val,id});
}
}
for(int i=1;i<=q;i++){
ll x;
cin>>x;
qr.push_back({x,i});
}
sort(mp.begin(),mp.end());
sort(qr.begin(),qr.end());
int j=0;
for(auto [x,id]:qr){
while(j<mp.size()&&mp[j].first<=x){
int u=mp[j].second;
int nx=u/(m+1);
int ny=u%(m+1);
vis[u]=1;
if(nx==1) ans++;
for(int k=0;k<4;k++){
int tx=nx+dir[k][0];
int ty=ny+dir[k][1];
if(tx<1||tx>n||ty<1||ty>m) continue;
int v=tx*(m+1)+ty;
if(vis[v]) merge(u,v);
}
j++;
}
res[id]=ans;
}
for(int i=1;i<=q;i++) cout << res[i] << endl;
}