跟着付队一起打的第二场gym,差点就被付队爆0了,还好趁他不注意切了两个水题(付队tql)
题意:有n个不同版本的野兽,定义属性:第 i 个野兽有 i 个眼睛和 h[i] 个角,你可以任意从中选择一个野兽进行进化,每次进化角数量必须增加,而且进化后假设有a 个眼睛 b个角,假设h[i]=b,那么abs(a-i)<=w,否则不能进化,求最多的进化次数。
思路:从大到小枚举h[i]的值,设d[i]为从第 i 个野兽开始进化所能得到的答案,如果对于 j,h[j]<h[i]且abs(i-j)<=w,那么d[j]=max(d[j],d[i]+1)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5005,inf=1e9;
int d[maxn],h[maxn];
int main()
{
int n,w,p=0,ans=0;
scanf("%d%d",&n,&w);
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
if(h[i]>h[p])p=i;
}
int m=n;
while(m--)
{
for(int i=1;i<=n;i++)
if(h[i]<h[p]&&abs(i-p)<=w)
{
d[i]=max(d[i],d[p]+1);
ans=max(ans,d[i]);
}
h[p]=inf;p=0;
for(int i=1;i<=n;i++)
if(h[i]!=inf&&h[i]>h[p])p=i;
}
printf("%d\n",ans);
}
题意:有n个房子的坐标,你要建立公交车站,使得每个房子离最近的车站不过10公里,求最少的车站。
思路:直接贪心,从左往右遍历房子,如果一个房子没被覆盖,就在他右边10公里建车站即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,x,p=-100,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
if(x>p+10)
ans++,p=x+10;
}
printf("%d\n",ans);
}
}
题意:给一些有向边,如果两个点可以互达,那么这两个点属于同一组,求你给有向图分组。
思路:就是强连通裸题。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=205;
vector<int>G[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
stack<int>S;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!pre[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}else if(!sccno[v])
{
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
for(;;){
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc(int n){
dfs_clock=scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
for(int i=0;i<n;i++)
if(!pre[i])dfs(i);
}
int main()
{
int T,a,b,n,m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)G[i].clear();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
}
find_scc(n);
printf("%d\n",scc_cnt);
}
}
付队写的,我还有事先溜了,贴付队线段树代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=400010;
struct in{
int opt,t,val,id;
in(){}
in(int oo,int tt,int vv):opt(oo),t(tt),val(vv){}
friend bool operator <(in w,in v){
if(w.t^v.t) return w.t<v.t;
return w.opt<v.opt;
}
}s[maxn];//1 add, 2query 3 del
int cnt,ans[maxn],sum[maxn],b[maxn],tot;
void add(int Now,int L,int R,int pos,int val)
{
sum[Now]+=val;if(L==R) return ;
int Mid=(L+R)>>1;
if(pos<=Mid) add(Now<<1,L,Mid,pos,val);
else add(Now<<1|1,Mid+1,R,pos,val);
}
int query(int Now,int L,int R,int K)
{
if(L==R) return L; int Mid=(L+R)>>1;
if(sum[Now<<1]>=K) return query(Now<<1,L,Mid,K);
return query(Now<<1|1,Mid+1,R,K-sum[Now<<1]);
}
int main()
{
int C=0,T,N,M,Mx,op,x,y,z;
scanf("%d",&T);
while(T--){
scanf("%d",&N); tot=0; cnt=0;
rep(i,1,N){
scanf("%d%d%d",&op,&x,&y);
if(op==1) {
scanf("%d",&z);
s[++cnt]=in(1,x,y);
s[++cnt]=in(3,z,y);
b[++tot]=y;
}
else s[++cnt]=in(2,x,y);
s[cnt].id=i;
ans[i]=0;
}
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-(b+1);
sort(s+1,s+cnt+1);
rep(i,1,tot<<1) sum[i]=0;
rep(i,1,cnt){
//cout<<s[i].opt<<" : "<<s[i].t<<" "<<s[i].val<<" "<<s[i].id<<endl;
if(s[i].opt!=2){
int pos=lower_bound(b+1,b+tot+1,s[i].val)-b;
add(1,1,tot,pos,(s[i].opt==1)?1:-1);
}
else {
if(sum[1]<s[i].val) ans[s[i].id]=-1;
else ans[s[i].id]=query(1,1,tot,s[i].val);
//cout<<s[i].val<<" ! "<<sum[1]<<" "<<ans[s[i].id]<<endl;
}
}
printf("Case %d:\n",++C);
rep(i,1,N) {
if(ans[i]==0) continue;
if(ans[i]==-1) puts("-1");
else printf("%d\n",b[ans[i]]);
}
}
return 0;
}
题意:求一个最大的子矩阵,子矩阵的和要么为0要么为1。
贴付队单调队列代码(明天回来补完):
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1010;
char c[maxn][maxn];
int ans[maxn][maxn],sum[maxn][maxn];
int main()
{
int T,N,M,Mx;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M); Mx=0;
rep(i,1,N)
rep(j,1,M){
c[i][j]=getchar();
while(c[i][j]!='0'&&c[i][j]!='1') c[i][j]=getchar();
//scanf("%d",&c[i][j]),
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(c[i][j]=='1');
}
rep(i,1,N)
rep(j,1,M){
ans[i][j]=ans[i-1][j-1]-1;
if(ans[i][j]<1) ans[i][j]=1;
while(i+ans[i][j]<=N&&j+ans[i][j]<=M&&(sum[i+ans[i][j]][j+ans[i][j]]-sum[i-1][j+ans[i][j]]-sum[i+ans[i][j]][j-1]+sum[i-1][j-1]<=1)) ans[i][j]++;
Mx=max(Mx,ans[i][j]);
}
printf("%d\n",Mx);
}
return 0;
}
本文深入解析了一场算法竞赛中遇到的多个挑战性问题,包括野兽进化游戏、公交站选址、有向图分组等,提供了详细的代码实现和解题思路,如贪心算法、强连通分量和单调队列等高级数据结构的应用。

被折叠的 条评论
为什么被折叠?



