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

23ICPC澳门站补题

原题链接
补题思路参考 1 2 3

J BFS

传送系统两个操作

  • 立即传送到(i+ai)modn(i+a_i)\bmod n(i+ai)modn
  • 调整ai←ai+1a_i\gets a_i+1aiai+1,也就相当于传送到ai+1a_i+1ai+1的位置,到aia_iai后再向前跳一个
    BFS遍历找最短路
const int N=1e5+5,mod=1e9+7,inf=1e9+10;
int vis[N][2],dis[N][2];
void solve() {memset(dis,0x3f,sizeof dis);int n,x;cin>>n>>x;vector<int>a(n+1);forr(i,0,n-1)cin>>a[i];queue<pii>q;q.push({0,0});//{位置,是否可以向前跳}//此时还没跳到a_i的地方 不能向前dis[0][0]=0;while (q.size()){auto [i,st]=q.front();q.pop();if(vis[i][st])continue;vis[i][st]=1;//向下一个点跳int nxt=(i+a[i])%n;//跳到a_iif(dis[nxt][1]>dis[i][st]+1){dis[nxt][1]=dis[i][st]+1;q.push({nxt,1});}if(st==1){//跳到这个点 可以+1nxt=(i+1)%n;if(dis[nxt][1]>dis[i][1]+1){dis[nxt][1]=dis[i][1]+1;q.push({nxt,1});}}}cout<<dis[x][1]<<endl;
}

I 贪心 dp

void solve(){int a,b,m;cin>>a>>b>>m;vector<int>dp(m+1,0);dp[0]=2;//dp[i] 到时间i 两道具都用  用前面的转移到后面/*两种思路1.等到R刷新好了就用 周期是b2.R刷新好了之后 等待H冷却好了再用R 周期是 ceil(b/a)*a=(b+a-1)/a *a*/int ans=0;forr(i,0,m){if(dp[i]){ans=max(dp[i]+(m-i)/a,ans);//后面的不再用b//向后转移if(i+b<=m)dp[i+b]=max(dp[i+b],dp[i]+1+b/a);//+1是因为H冷却好了if(i+(b+a-1)/a*a<=m)dp[i+(b+a-1)/a*a]=max(dp[i+(b+a-1)/a*a],dp[i]+1+(b+a-1)/a);}}cout<<ans*160<<endl;//废片 一开始只想了一种以b为周期的策略// if(a>b){//     cnt=2+m/b;//     cout<<1<<' '<<cnt<<endl;// }else {//     int rd=m/b,dis=m%b;//     int cnta=(b+a-1)/a;//     cout<<cnta<<' '<<rd<<endl;//     cnt=cnta*rd+(dis/a+1)+1;//     cout<<cnta*rd<<' '<<(dis/a+1)<<' '<<(rd+1)<<endl;//     cout<<cnt<<endl;// // if(a==b){// //     cnt=2*(m/b+1);// //     cout<<2<<' '<<cnt<<endl;// // }else{// //     int per=(b+a-1)/a;// //     cnt=per*(m/b+1)+1;// //     cout<<3<<' '<<cnt<<endl;// }
}

D 思维 并查集 暴力

注意题设条件:可以保证 G 的最大度数最多为 3
诱导子图有n个点,红蓝总共最多有3n23n\over 223n条边
满足合法,最少有2(n−1)2(n-1)2(n1)
3n2≥2(n−1){3n\over 2}\geq 2(n-1)23n2(n1),得n≤4n\leq 4n4
枚举n暴力找点

const int N=1e5+2,mod=1e9+7,inf=1e9+10;
int fa[N],vis[N];
vector<pii>ve[N];
set<pii>e[N];
int find(int x){return fa[x]==x?x:find(fa[x]);
}
void merge(int x,int y){int fx=find(x),fy=find(y);fa[fx]=fy;
}
int check(vector<int>v){//验证蓝边是否也联通for(auto i:v)fa[i]=i;//两两枚举红联通集中的点 在蓝边里合并 看是否能合成一个联通集forr(i,0,3){forr(j,0,3)if(e[1].count({v[i],v[j]}))merge(v[i],v[j]);}forr(i,1,3)if(find(v[i])!=find(v[0]))return 0;return 1;
}
void dfs(int now,vector<int>&v){vis[now]=1;v.push_back(now);if(v.size()==4)return;for(auto [to,c]:ve[now]){if(c==0&&vis[to]==0)dfs(to,v);//只找红边}
}
//关键在于找出两种颜色最小联通的情况 边的数量2(m-1)
//根据题设每个点最多3条边 3m/2>=2(m-1)  m<=4
void solve(){int n,m;cin>>n>>m;forr(i,1,m){int u,v,c;cin>>u>>v>>c;ve[u].push_back({v,c}),ve[v].push_back({u,c});e[c].insert({u,v});}int ans=0;//sz=2,3for(auto [u,v]:e[0]){if(e[1].count({u,v})||e[1].count({v,u})){ans++;//2pii rnxt,bnxt;rnxt=bnxt=pii(-1,-1);for(auto [to,c]:ve[u])if(to!=v)rnxt={to,c};for(auto [to,c]:ve[v])if(to!=u)bnxt={to,c};if(rnxt.fir==-1||bnxt.fir==-1)continue;if(rnxt.fir==bnxt.fir&&rnxt.sec!=bnxt.sec)ans++;//3}}// sz=1ans+=n;// sz=4 暴力找四个点 验证是否合法forr(i,1,n){if(vis[i]==0){vector<int>getv;dfs(i,getv);// for(auto x:getv)cout<<x<<' ';cout<<endl;if(getv.size()==4)ans+=check(getv);}}cout<<ans<<endl;
}

A 思维 问题转化

const int N=4e3+2,mod=1e9+7,inf=1e9+10;
string s[N];
int a[N][N],nd[N][N];
//关键在于发现取与不取后值的变化
//-1如果先都取上(达到最小值) 不取就相当于+1 
//取一个1也相当于+1 
//关注从最小值到目标值需要多少个+1
void solve(){int n;cin>>n;vector<int>row(n+1),col(n+1);forr(i,1,n){cin>>s[i];forr(j,0,n-1)a[i][j+1]=(s[i][j]=='-'?-1:1);}forr(i,1,n)cin>>row[i];forr(i,1,n)cin>>col[i];//统计每行-1的和priority_queue<pii>q;//使用堆 优先填补需求+1多的forr(i,1,n){int cnt=0;forr(j,1,n)if(a[i][j]<0)cnt+=a[i][j];if(cnt>row[i])rno;//return no;else {q.push({row[i]-cnt,i});//需要多少个+1}}//统计每列需要+1的位置 和每行需要+1的位置交叉forr(j,1,n){int cnt=0;forr(i,1,n)if(a[i][j]<0)cnt+=a[i][j];if(cnt>col[j])rno;else if(col[j]-cnt>q.size())rno;//每列的+1不能满足需要的vector<pii>tp;//把当前需要+1的行全遍历一遍while(q.size())tp.push_back(q.top()),q.pop();for(auto [d,id]:tp){if(cnt<col[j]){cnt++;d--,nd[id][j]=1;//这里需要一个+1}if(d>0)q.push({d,id});//还没填满该行需要的1 放回去}}if(q.size())rno;cout<<"yes"<<endl;forr(i,1,n){forr(j,1,n){if(nd[i][j]==1)cout<<(a[i][j]==1);//需要1且正好有1else cout<<(a[i][j]==-1);//不需要1 把-1算上}cout<<endl;}
}

E 单调栈找逆序对 拓扑排序


a:1 3 2 (3->2)
b:3 2 1
逆序一定有边

const int N = 1e5+10, C = 1e6 + 10, mod =998244353, inf = 1e9 + 10;
vector<int>tr[N];
void solve()
{int n;cin>>n;vector<int>a(n+1,0),b(n+1,0),deg(n+1,0);forr(i,1,n)cin>>a[i];forr(i,1,n)cin>>b[i];int ans=0;//单调栈找逆序 逆序的一定有边stack<int>st;//小字典序 forr(i,1,n){while (st.size()&&st.top()<a[i])st.pop();if(st.size()&&st.top()>a[i]){tr[st.top()].push_back(a[i]);deg[a[i]]++;ans++;}st.push(a[i]);}while(st.size())st.pop();//大字典序 前面大->小的边在大字典序中不会产生逆序 不会重复计算forr(i,1,n){while (st.size()&&st.top()>b[i])st.pop();if(st.size()&&st.top()<b[i]){tr[st.top()].push_back(b[i]);deg[b[i]]++;ans++;}st.push(b[i]);}//成图后 大小字典序分别拓扑验证是否合理int ac,bc;ac=bc=0;int ai,bi;ai=bi=0;vector<int>aj(n+1,0),bj(n+1,0);priority_queue<int,vector<int>,greater<int>>qa;//小根堆priority_queue<int>qb;//默认大根堆auto degt=deg;forr(i,1,n)if(deg[i]==0)qa.push(i),qb.push(i);while (qa.size()){int now=qa.top();qa.pop();aj[++ai]=now;for(auto x:tr[now]){if(--deg[x]==0)qa.push(x);}}while (qb.size()){int now=qb.top();qb.pop();bj[++bi]=now;for(auto x:tr[now]){if(--degt[x]==0)qb.push(x);}}if((ai!=n||bi!=n)&&ans!=0)rno;else if(aj!=a||bj!=b)rno;else {cout<<"Yes"<<endl<<ans<<endl;forr(i,1,n){for(auto x:tr[i]){cout<<i<<' '<<x<<endl;}}}
}

H 树形dp 组合数学 可重复排列

约束:选择停在子树now的车数量范围sznow≤cur≤sznow+depnowsz_{now}\leq cur\leq sz_{now}+dep_{now}sznowcursznow+depnow,多出来的可以向根节点推最多depnowdep_{now}depnow

const int N = 1e5+10, C = 1e6 + 10, mod =998244353, inf = 1e9 + 10;
vector<int>tr[N];
int sz[N],dep[N],fact[N],ifac[N];
int qpow(int x,int p=mod-2){int res=1;for(;p;p>>=1,(x*=x)%=mod)if(p&1)(res*=x)%=mod;return res;
}
void init(int n){fact[0]=1;forr(i,1,n)fact[i]=fact[i-1]*i%mod;ifac[n]=qpow(fact[n]);reforr(i,0,n-1)ifac[i]=(i+1)*ifac[i+1]%mod;
}
vector<int>dp[N];//dp[i] i点的状态
void dfs(int now=1){//本节点子树数据更新sz[now]=1;for(auto x:tr[now])dep[x]=dep[now]+1,dfs(x),sz[now]+=sz[x];//子树合并int L=0,R=0;//L,R是已合并子树的车数范围static int g[N],tmp[N];//g已合并子树的方案数 g[0]=1;//now一个点的情况for(auto x:tr[now]){forr(i,L+sz[x],R+sz[x]+dep[x])tmp[i]=0;//新合并的用tmp存用到哪里初始化哪里forr(i,L,R){forr(j,sz[x],sz[x]+dep[x]){//枚举停在x子树中的车数// sz[x](把x子树填满)<=j<=sz[x]+dep[x](可以向上填最多dep[x]个)// 乘法原理 已合并的子树方案数*目前子树方案数(tmp[i+j]+=g[i]*dp[x][j-sz[x]])%=mod;//用子树的dp更新本层 j-sz[x]是向上超出的层数}}L+=sz[x],R+=sz[x]+dep[x];//更新子树范围forr(i,L,R)g[i]=tmp[i];//新子树合并进去}//计算本节点dp:本节点方案数dp[now].resize(dep[now]+1);forr(ch,L,R)//枚举now的子树车数forr(cur,sz[now],sz[now]+dep[now]){//枚举now下面的子树车数 更新方案数if(ch<=cur)(dp[now][cur-sz[now]]+=g[ch]*ifac[cur-ch])%=mod;//*ifac[cur-ch] cur-ch是选择停在now点的车数 用到了可重全排列 /*可重全排列 eg. 1 1 2 1有4!/3!=4个排列情况 n!/val! val是重复元素的个数n!可以在最后计算总结果时乘上,进行答案的全排列*/}
}
void solve()
{int n;cin>>n;forr(i,2,n){int f;cin>>f;tr[f].push_back(i);}init(n);dfs();int ans=(dp[1][0]*fact[n])%mod;cout<<ans<<endl;
}
http://www.dtcms.com/a/454508.html

相关文章:

  • 怎样做淘宝的导购网站推广宣传片制作网站
  • 51zwd做网站淘宝网中国站电脑版登录
  • 快速搭建网站 开源软件开发工程师多少钱一个月
  • vue知识点-列表渲染+key
  • 花茶网站模板装修全包
  • discuz企业网站模板陕西住房城乡建设网站
  • 哪些网站可以做海报网站建设需要摊销几年
  • Mac怎么搭建网站开发环境微信公众号怎么进行网站建设
  • 深圳网站设计服务公如何创建个人博客wordpress
  • 国外网站网站wordpress技术教程
  • 网站建设 的公司哪家好提供app开发公司报价
  • 做网站自动上传文章网络技术推广服务
  • 网站建设与开发定制怎么做局域网网站
  • 3网站建设电子商务网站建设详细策划书
  • 《AI智脉速递》2025 年 9月22 日 - 10月7日
  • win7做本地网站360如何做免费的网站
  • 石碣东莞网站建设wordpress 站群
  • 中交通力建设股份有限公司网站南京时事重大新闻
  • 网站网站建设考虑要素域名查询官网入口
  • 网站的内容更新网站的开发工具和运行环境
  • 免费app制作网站网页升级紧急通知在线
  • ArrayList 在序列化时的重写重写了 writeObject()特殊处理的原因
  • 南山做网站推广乐云seo买一个普通商标多少钱
  • 江西新农村建设权威网站在那可以做公司网站
  • 购物网站的设计头像制作免费生成器
  • 怎么做ppt教程网站网页设计登录注册页面代码
  • 【51单片机】【protues仿真】基于51单片机贪吃蛇游戏系统
  • 昆明学校网站设计公司网页设计项目模板代码
  • 有没有做培养基的网站已备案网站想关闭
  • 【Canvas与旗帜】油管五常之印度旗恒河之眼版