nflsoi 7.31 题解
A.#1845 炸弹
题意
思路
不是这个难,是我当时太唐。
记录上一个炸弹出现位置 laslaslas。当 位置 iii 无炸弹且 i−las=di-las=di−las=d,那么后面的炸弹肯定引爆不了,再次放一个炸弹即可。
C.#12391 最小正方形 / TopCoder 12976 Mininum Square
题意
平面上有 nnn 个点。给定两个长度为 nnn 的整数数组 xxx 和 yyy,分别表示这些点的坐标。nnn 个点的坐标依次为 (x1,y1),(x2,y2),...,(xn,yn)(x_1,y_1),(x_2,y_2),...,(x_n,y_n)(x1,y1),(x2,y2),...,(xn,yn)。
你需要在平面上绘制一个正方形。该正方形的顶点必须具有整数坐标,且各边必须与坐标轴平行。还有一个额外约束:给定的 nnn 个点中至少有 kkk 个必须严格位于正方形内部(即不在边界上)。
给定 x,yx,yx,y 和整数 kkk,输出满足上述约束的最小可能正方形面积。
2≤n≤1002\le n\le 1002≤n≤100,∣xi∣,∣yi∣≤109|x_i|,|y_i|\le 10^9∣xi∣,∣yi∣≤109。
思路
注意是正方形。其实也不难。
坐标值超级大,但是点数很小,那就先离散化。方便二维数组存储。
这题可以 O(n4)O(n^4)O(n4) 乱过:枚举一个子矩形的左上角和右下角 (i,j)(i,j)(i,j) 和 (p,q)(p,q)(p,q)(离散化后坐标),容易用二维前缀和计算矩形上点的个数(包含边界)。当个数大于 kkk,选矩形较长边边长 +2+2+2 作为边长形成正方形。+2+2+2 是为了除去边界的影响,记得映射回离散化前的坐标。
你知道我多怕面积爆 long long
吗?
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=155,inf=3e14;
ll n,k;
ll x[N],y[N];
ll xx[N],yy[N],nx,ny;
ll G[N][N],s[N][N];
int main()
{scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&x[i]);xx[i]=x[i];}scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&y[i]);yy[i]=y[i];}sort(xx+1,xx+n+1);sort(yy+1,yy+n+1);nx=unique(xx+1,xx+n+1)-xx-1;ny=unique(yy+1,yy+n+1)-yy-1;for(int i=1;i<=n;i++){x[i]=lower_bound(xx+1,xx+nx+1,x[i])-xx;y[i]=lower_bound(yy+1,yy+ny+1,y[i])-yy;G[x[i]][y[i]]++;}for(int i=1;i<=nx;i++)for(int j=1;j<=ny;j++)s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+G[i][j];scanf("%lld",&k);ll ans=inf;for(int i=1;i<=nx;i++){for(int j=1;j<=ny;j++){for(int p=i;p<=nx;p++){for(int q=j;q<=ny;q++){if(s[p][q]-s[p][j-1]-s[i-1][q]+s[i-1][j-1]>=k){// cout<<xx[p]-xx[i]+2<<" "<<yy[q]-yy[j]+2<<endl;ans=min(ans,max(xx[p]-xx[i]+2,yy[q]-yy[j]+2));}}}}}cout<<ans*ans;return 0;
}
D.#12712 太空飞船 / TopCoder 14104 Fleet Funding
题意
乔治负责组建一支太空飞船舰队。每艘飞船由 mmm 个不同的部件组成,编号从 111 到 mmm。
乔治目前没有任何部件,但他拥有无限的预算。有 nnn 个工厂可以生产他所需的部件,这些工厂的信息由数组 kkk 、aaa 和 bbb 描述。对于每个有效的 iii,存在一个工厂,其生产限制如下:
- 该工厂资源有限,因此最多只能生产 kik_iki 个部件;
- 该工厂只能生产编号在 aia_iai 到 bib_ibi 之间的部件;
- 同一个工厂可以生产多个相同编号的部件,只要该工厂生产的总部件数不超过 kik_iki 即可。
在满足这些限制的情况下,计算乔治最多能建造多少艘完整的太空飞船。
思路
如果正着硬求能造多少艘肯定很难很烦很难调,不妨反过来二分答案,二分能造多少艘并根据现有条件判断其是否合法。
传奇右端点排序贪心,因为在前面尽量不浪费能够制作后面零件的机会。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=56;
ll m,n;
struct facto
{ll cnt,l,r;
}a[N];
bool cmp(facto x,facto y)
{return x.r<y.r;
}//按右端点排序,在前面不浪费能够制作后面零件的机会
ll cnt[N];
bool check(ll mid)
{for(int i=1;i<=n;i++)cnt[i]=a[i].cnt;for(int i=1;i<=m;i++){ll tar=mid;for(int j=1;j<=n;j++){if(a[j].l<=i&&i<=a[j].r){ll d=min(cnt[j],tar);tar-=d;cnt[j]-=d;}}if(tar)return 0;//mid艘飞船造不完i零件}return 1;
}
int main()
{scanf("%lld%lld",&m,&n);for(int i=1;i<=n;i++)scanf("%lld",&a[i].cnt);for(int i=1;i<=n;i++)scanf("%lld",&a[i].l);for(int i=1;i<=n;i++)scanf("%lld",&a[i].r);sort(a+1,a+n+1,cmp);ll l=0,r=1e13,ans=0;while(l<=r){ll mid=(l+r)>>1;if(check(mid))ans=mid,l=mid+1;else r=mid-1;}printf("%lld",ans);return 0;
}
也不知道 nflsoj 为什么输入那么多次 nnn。
F.#2899 查询最大字段和 / SP2916 GSS5
我的博客
G.#4543 交朋友 / 洛谷 P8907 USACO22DEC Making Friends
题意
FJ 的 NNN 头编号为 1∼N1 \sim N1∼N 的奶牛之中,初始时有 MMM 对朋友。奶牛们一头一头地离开农场去度假。第 iii 天,第 iii 头奶牛离开了农场,同时第 iii 头奶牛的所有仍在农场的朋友互相都成为了朋友。问总共建立了多少新的朋友关系?
2≤N≤2×1052 \le N \le 2 \times 10^52≤N≤2×105,1≤M≤2×1051 \le M \le 2 \times 10^51≤M≤2×105。
思路
这题赛时偷看了题解 qwq,什么时候才会做这种启发式合并题。
奶牛 iii 和 jjj 最终是朋友(i<ji<ji<j),要在原图中存在一条 i→ji\rightarrow ji→j 的路径,使得不包括端点,路径上的所有点编号都小于 iii,考虑每次计算 iii 的贡献,有多少符合条件的 jjj。
从小到大枚举 iii,对于 iii 的相邻点,先将相邻点中编号大于 iii 的放进 set
里面,然后用并查集将编号小于 iii 的相邻点和 iii 按秩合并(启发式合并),将点集向祖先合并。对于 iii 的祖先 find_fa(i)
,记得除去 i→ii\rightarrow ii→i ——用 set
就是因为它可以去重和 logn\log nlogn 删除。那么 iii 带来的贡献就是 Set[find_fa(i)].size()
,对应着符合条件 jjj 的数量。
最后记得减去原有的 mmm 对关系。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2e5+9,inf=3e14;
ll n,m;
vector<ll>G[N];
set<ll>s[N];
ll fa[N],siz[N];
ll fz(ll x)
{while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
void join(ll u,ll v)
{u=fz(u),v=fz(v);if(u==v)return;if(siz[u]<siz[v])swap(u,v);fa[v]=u;siz[u]+=siz[v];for(auto t:s[v])s[u].insert(t);
}
int main()
{scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;for(int i=1;i<=m;i++){ll u,v;scanf("%lld%lld",&u,&v);G[u].push_back(v);G[v].push_back(u);}ll ans=0;for(int i=1;i<=n;i++){for(auto v:G[i])if(v>i)s[i].insert(v);for(auto v:G[i])if(v<i)join(i,v);if(s[fz(i)].find(i)!=s[fz(i)].end())s[fz(i)].erase(i);ans+=s[fz(i)].size();}printf("%lld",ans-m);return 0;
}