Day5下
T1

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<cmath> using namespace std; const int N=1010; int n,m,k,p; int to[N],nex[N]; int a[N][N]; int main() { freopen("rotate.in","r",stdin); freopen("rotate.out","w",stdout); scanf("%d%d%d",&n,&p,&k); for(int j=1;j<=n;j++) to[j]=j; for(int i=1;i<=p;i++) { scanf("%d",&m);a[i][0]=m; for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); } for(int i=p;i>=1;i--) { memset(nex,0,sizeof nex);m=a[i][0]; for(int j=2;j<=m;j++) nex[a[i][j-1]]=a[i][j]; nex[a[i][m]]=a[i][1]; for(int j=1;j<=n;j++) if(nex[to[j]]) to[j]=nex[to[j]]; } for(int j=1;j<=n;j++) printf("%d ",to[j]); return 0; }
置换,没学过的话模拟就行。考察理解题意了。
正着做:置换的性质。(不知道也能做)
T2

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<cmath> using namespace std; const int N=1e4+100; int n,a,b,c,d; int q[N]; long long ans; int main() { freopen("range.in","r",stdin); freopen("range.out","w",stdout); scanf("%d%d%d%d%d",&n,&a,&b,&c,&d); for(int i=1;i<=n;i++) scanf("%d",&q[i]); for(int i=1,j;i<=n;i++) { int ans1,ans2; ans1=ans2=q[i]; if(ans1<a||ans2>d) continue; j=i; for(j;j<=n;j++) { ans1&=q[j];ans2|=q[j]; if(ans1<a||ans2>d) break; if(ans1<=b&&ans2>=c) ans++; } } cout<<ans<<endl; return 0; }

#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<cmath> #include<ctime> using namespace std; typedef long long LL; const int N=1e5+7; const LL P=1e9+7; LL ans; int s[N],sta[N][21],sto[N][21]; int worka(int l,int r) { int L=r-l+1; int t=log2(L); return sta[l][t]&sta[r-(1<<t)+1][t]; } int worko(int l,int r) { int L=r-l+1; int t=log2(L); return sto[l][t]|sto[r-(1<<t)+1][t]; } int n,a,b,c,d; int main() { freopen("range.in","r",stdin); freopen("range-me.out","w",stdout); scanf("%d%d%d%d%d",&n,&a,&b,&c,&d); for(int i=1;i<=n;i++) { scanf("%d",&s[i]); sta[i][0]=sto[i][0]=s[i]; } //预处理倍增,下一步能O(1)查询区间值 for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) if(i+(1<<j)-1 <=n ) { sta[i][j]=sta[i][j-1]&sta[i+(1<<j)][j-1]; sto[i][j]=sto[i][j-1]|sto[i+(1<<j)][j-1]; } //查找区间(具有单调性) for(int i=1;i<=n;i++) { int andans,orans; // andans=orans=s[i]; int j=i; while(j<=n) { int L=j,R=n+1,mid; andans=worka(i,j); orans=worko(i,j); while(R-L>1) { mid=(L+R)>>1; if(worka(i,mid)==andans&&worko(i,mid)==orans) L=mid; else R=mid; } if(andans>=a&&andans<=b&& orans>=c&&orans<=d) ans+=L-j+1; j=L; } } cout<<ans%P; }
先固定左端典,向右搜,查找区间个数。
怎么优化,二分 +倍增。
本来我想’与‘和’或‘是不满足 前缀差等于区间值的性质的。
其实我的想法太狭隘了,仔细想想:无论是’与‘还是’或‘ 都满足两段区间O(1)合成更大区间的性质。
比如f[1,6] & f[3,9], 可以看成f[1,3] & f[3,6]&f[6,9] &f[3,6] 一个数和本身的’‘与’还是本身无影响。
然后就能通过二分把n^n变成nlogn,
T3

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<cmath> using namespace std; const int N=1009; const int P=1e9+7; int n,k; int h[N],nex[N*2],to[N*2],cnt; int w[N],sum[N],tot[N];//子树节点数,根到这的和 int x,y; void add() { scanf("%d%d",&x,&y); to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt; to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt; } int vis[N];int ans; void dfs(int Tot,int Sum,int last) { if(Tot==k) { int ss=Sum; for(int i=1;i<=n;i++) if(vis[i]) for(int j=h[i];j;j=nex[j]) if(!vis[to[j]]) Sum++; Sum=n-1-Sum; ans=(1LL*ans+1LL*(1<<Sum)%P)%P; Sum=ss; } if(Tot>k) return ; for(int i=last;i<=n;i++) if(vis[i]) { int is=0; for(int j=h[i];j;j=nex[j]) if(!vis[to[j]]) { vis[to[j]]=1; dfs(Tot+w[to[j]],Sum+1,i); vis[to[j]]=0; is=1; } } } int main() { freopen("fruit.in","r",stdin); freopen("fruit.out","w",stdout); scanf("%d%d",&n,&k); int is=1; for(int i=1;i<=n;i++) { scanf("%d",&w[i]); if(!w[i]) is=0; } for(int i=1;i<n;i++) add(); vis[1]=1; dfs(w[1],0,1); if(!is) ans--; cout<<ans; return 0; }

#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; typedef long long LL; const LL P= 1e9+7; const int N=1009; int n,k; int a[N]; int h[N],nex[N*2],to[N*2],cnt; LL f[N][N]; int x,y; void add() { scanf("%d%d",&x,&y); to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt; to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt; } int dfs(int x,int fa) { int sum=1,tmp; for(int i=h[x];i;i=nex[i]) { if(to[i]==fa) continue; for(int j=0;j<=n-a[to[i]];j++) f[to[i]][j+a[to[i]]]=f[x][j]; tmp=dfs(to[i],x); for(int j=0;j<=n;j++) f[x][j]=(f[x][j]*(1<<(tmp-1))+f[to[i]][j])%P; sum+=tmp; } return sum; } int main() { freopen("d.in","r",stdin); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++) add(); f[1][a[1]]=1; dfs(1,0); printf("%lld",(f[1][k])); }
说到T3我就不得不吐槽一下,我投入了整套题考试总时间中超过一半的时间,结果0分。遗憾啊。
搜索 搜重了,不知道怎么去重。
正解是个背包(我没看出来。。。),f[i][j]表示在i节点及其子树中拿j个果子的方案数,。
转移的话先遍历子节点,再根据已有信息更新其他字节点,和其父节点。
dp[x][j] = ((1<<(tmp-1) * dp[x][j] % mod + dp[son][j])% mod
(除了直接相连的边必须断掉之外,其他边怎样都行,2^n 种状态。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App