当前位置: 首页 > news >正文

2025.10.31写题

P5309 [Ynoi2011] 初始化

省选/NOI-

操作一y+x,y+2*x...到大于n,加z

操作二求【l,r】的和

分块

对于x>根号n,考虑暴力,每次操作复杂度根号n

对于x<=根号n,预处理答案

由于y<x不难想到n在取模x的情况下被分块,pre[i][x]表示跨度为x的情况下1~i的加成和,suf[i][x]表示在取模x的情况下i~x的加成和

x<=根号n的情况答案可以分为,原块的和于暴力加上的和,求这个复杂度为根号n,与小于根号n的操作加成和,复杂度为根号n

AcCode:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define  endl '\n'
const int N=2e5+10;
const int M=450;
const ll mod=1e9+7;
int n,m,len,bnum,b[N],bl[M],br[M];
ll a[N],pre[M][M],suf[M][M],sum[M],x,y,z,op,l,r;
void init()
{len=sqrt(n);bnum=(n+len-1)/len;for(int i=1;i<=n;i++){b[i]=(i-1)/len+1;sum[b[i]]+=a[i];}for(int i=1;i<=bnum;i++){bl[i]=(i-1)*len+1;br[i]=min(i*len,n);}
}
ll query(int l,int r)
{ll res=0;if(b[l]==b[r]){for(int i=l;i<=r;i++)res+=a[i];}else{for(int i=b[l]+1;i<=b[r]-1;i++)res+=sum[i];for(int i=l;i<=br[b[l]];i++)res+=a[i];for(int i=bl[b[r]];i<=r;i++)res+=a[i];}for(int i=1;i<=len;i++){int bx=(l-1)/i+1,by=(r-1)/i+1;if(bx==by)res+=pre[i][(r-1)%i+1]-pre[i][(l-1)%i];else{ll cnt=by-bx-1;res+=suf[i][(l-1)%i+1];res+=pre[i][(r-1)%i+1];res+=cnt*pre[i][i];}}return res%mod;
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];init();for(int i=1;i<=m;i++){cin>>op;if(op==1){cin>>x>>y>>z;if(x<=len){for(int j=y;j<=x;j++)pre[x][j]+=z;for(int j=y;j>=1;j--)suf[x][j]+=z;}else{for(int j=y;j<=n;j+=x){a[j]+=z;sum[b[j]]+=z;}}}else {cin>>l>>r;cout<<query(l,r)<<endl;}}return 0;
}

和ex的一道题,分块居然卡常,时限只有500ms,不能随时取模,不然会被卡

P3645 [APIO2015] 雅加达的摩天楼

省选/NOI-

有n个大楼,编号0~n-1,有m个狗子,编号0~m-1
每只狗子有两个参数,idx表示狗子的初始大楼,jump表示狗子的跳跃能力
狗子在i位置,可以来到 i - jump 或 i + jump,向左向右自由跳跃,但不能越界
0号狗子有消息希望传给1号狗子,所有狗子都可帮忙,返回至少传送几次,无法送达打印-1

一眼bfs,考虑状态数是否合法

对于jump<=根号n,每个位置都有n*根号n个状态

对于jump>根号n,最多跳根号n回,状态最多m*根号n

n,m<=30000时,完全合法

AcCode:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define  endl '\n'
const int N=3e4+10;
bitset<N>vis[N];
int n,m,ed;
vector<int>edge[N];
struct node{int pos,p,ans;
};
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m;queue<node>q;for(int i=1;i<=m;i++){int b,p;cin>>b>>p;edge[b].push_back(p);if(i==1){q.push({b,p,0});vis[b][p]=true;}if(i==2)ed=b;}while(!q.empty()){auto [pos,p,ans]=q.front();q.pop();if(pos==ed){cout<<ans<<endl;return 0;}if(pos+p<=n-1&&!vis[pos+p][p]){vis[pos+p][p]=true;q.push({pos+p,p,ans+1});}if(pos-p>=0&&!vis[pos-p][p]){vis[pos-p][p]=true;q.push({pos-p,p,ans+1});}for(auto &d:edge[pos]){if(pos+d<=n-1&&!vis[pos+d][d]){vis[pos+d][d]=true;q.push({pos+d,d,ans+1});}if(pos-d>=0&&!vis[pos-d][d]){vis[pos-d][d]=true;q.push({pos-d,d,ans+1});}}}cout<<-1<<endl;return 0;
}

CF786 C. Till I Collapse

2400

这是一个最小划分问题人当然让人
给定一个长度为n的数组arr,考虑如下问题的解
数组arr划分成若干段子数组,保证每段不同数字的种类 <= k,返回至少划分成几段
打印k = 1, 2, 3..n时,所有的答案

当k<=根号n,暴力,每次o(n),复杂度n*根号n

当k>根号n,每段段长至少为根号n,故答案一定是小于等于根号n,并且随k增大,段数减少,最多根号n个分界点,将这根号n个分界点找出来,复杂度n*根号n*log(根号n)

AcCode:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define  endl '\n'
const int N=1e5+10;
int n,len,a[N],ans[N];
bool vis[N];
int query(int k)
{int cnt=0,ans=0,start=1;for(int i=1;i<=n;i++){if(!vis[a[i]]){if(cnt==k){for(int j=start;j<i;j++)vis[a[j]]=false;start=i;cnt=1;ans++;}else cnt++;vis[a[i]]=true;}}for(int i=start;i<=n;i++)vis[a[i]]=false;return ans+1;
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n;i++)cin>>a[i];len=sqrt(n);for(int i=1;i<=n;i++){if(i<=len)ans[i]=query(i);else{int l=i,r=n+1;int chk=query(i);while(l+1<r){int mid=(l+r)>>1;if(query(mid)==chk)l=mid;else r=mid;}ans[i]=chk;i=l;}}for(int i=1;i<=n;i++)if(ans[i]==0)ans[i]=ans[i-1];for(int i=1;i<=n;i++)cout<<ans[i]<<" ";return 0;
}

CF1039D You Are Given a Tree

2800

给你一棵树
一共有n个节点,给定n-1条边,所有节点连成一棵树
树的路径是指,从端点x到端点y的简单路径,k路径是指,路径的节点数正好为k
整棵树希望分解成尽量多的k路径,k路径的节点不能复用,所有k路径不要求包含所有点
打印k = 1, 2, 3..n时,k路径有最多有几条

跟上面一题是同一个问题,不过变成了在树上划分

对于一次路径长为k的划分,如何做到o(n)的复杂度呢?

考虑树形dp

在树上划分,贪心的来说,我更希望一条路径是曲折的,而不是一条向上的直线,如果有一个节点它有两颗子树与他划分正好能形成一条路径,那就直接划分,如果不划分,继续让其向上连,会影响其他子树连接,而且其形成时也是只加1,显然不优

我用mx1[x],mx2[x]表示x的子树中没有形成路径的最长路径和次长路径

当mx1[x]+mx2[x]+1>=k时,可以直接连接

单次查询o(n)

当k<=根号n,暴力,每次o(n),复杂度n*根号n

当k>根号n,每段段长至少为根号n,故答案一定是小于等于根号n,并且随k增大,段数减少,最多根号n个分界点,将这根号n个分界点找出来,复杂度n*根号n*log(根号n)

Accode:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define  endl '\n'
const int N=1e5+10;
vector<int>edge[N];
int n,len,cnt,f[N],mx1[N],mx2[N],ans[N],fa[N],dfn[N];
void dfs(int x)
{dfn[++cnt]=x;for(auto &y:edge[x]){if(y==fa[x])continue;fa[y]=x;dfs(y);}
}
int query(int k)
{int ans=0;for(int i=n,cur;i>=1;i--){cur=dfn[i];if(mx1[cur]+mx2[cur]+1>=k){ans++;f[cur]=0;}else f[cur]=mx1[cur]+1;if(f[cur]>mx1[fa[cur]])mx2[fa[cur]]=mx1[fa[cur]],mx1[fa[cur]]=f[cur];else if(f[cur]>mx2[fa[cur]])mx2[fa[cur]]=f[cur];}for(int i=1;i<=n;i++)f[i]=mx1[i]=mx2[i]=0;return ans;
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n-1;i++){int u,v;cin>>u>>v;edge[u].push_back(v);edge[v].push_back(u);}dfs(1);for(int i=1;i<=n;i++)ans[i]=-1;len=max(1,(int)sqrt(n*log2(n)));for(int i=1;i<=n;i++){if(i<=len)ans[i]=query(i);else{int l=i,r=n+1;int chk=query(i);while(l+1<r){int mid=(l+r)>>1;if(query(mid)==chk)l=mid;else r=mid;}ans[i]=chk;i=l;}}for(int i=1;i<=n;i++)if(ans[i]==-1)ans[i]=ans[i-1];for(int i=1;i<=n;i++)cout<<ans[i]<<endl;return 0;
}

注意虽然给了7s时限,但要转化成欧拉序,以循环的形式跑递归,不然dfs递归开销大,会超时

http://www.dtcms.com/a/554788.html

相关文章:

  • 兰州酒店网站建设招聘网58同城求职信息
  • 如何找招标信息
  • 北京盛赛车网站开发嘉定php网站开发培训
  • 爬虫数据去重:BloomFilter算法实现指南
  • 怎样自己做一个网站学校网站建设市场
  • 网站地图开发一站式做网站开发
  • JavaScript基础提升【三】
  • 百度网盘 做网站图床美区能和国区家庭共享吗
  • 基于3DGIS+BIM的智慧园区运维平台价值分享
  • atsec出席2025 PCI社区会议
  • 白云区建材网站建设推广wordpress换了ip
  • 旌阳区黄河开发建设网站建设工程施工司法解释
  • 外包网站设计哪家好怎样建立网站平台
  • 海南省工程建设定额网站网站建设的SOWT分析
  • 第1讲:彻底解决C++中资源泄露
  • CentOS 7上运行C程序
  • 网站建设有什么证.net程序员网站开发工程师
  • 安信可(Ai-Thinker)WiFi系列模块全解析:选型指南与应用洞察
  • 科技建站网站源码黄金网站app视频播放画质选择
  • 品牌网站设计图片企业软件管家
  • NetSuite 如何删除未生成的Memorized Transaction?
  • 秦皇岛优化网站排名邹城网站建设
  • 扁平化网站导航ui模板电子商务网站建设与管理理解
  • 有什么网站可以做毕业影像页面设计源代码
  • 金泽通 打造数字金融与商业融合新模式
  • 【算法专题训练】29、树的深度优先遍历
  • Rust + WebAssembly 实现多人在线共享白板:从设计到性能验证
  • 电脑什么网站可以做长图攻略阳光家园广州网站
  • 新网站建设平台上海做网站运维的公司
  • javan