あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2022.10.7模拟赛

2022.10.7模拟赛

T1

题面#

思路#

考试的时候并没有想到用什么高级的方法算这个玩意er,所以就直接先算 A×B,然后再×C,结果很合理地得了80分。
然而正解就是先算BC再×A,因为前者算完一次后是一个1000* 1000的矩阵,再和C算就是1000* 1000* 1000,加上之前的1000* 30* 1000复杂度是非常大的,不可能会A这道题,后者先算是30* 1000* 1000,然后和A算就是1000* 30* 1000,这样复杂度就降下来了,然后就A了。

code#

Copy
#include<bits/stdc++.h> #define int long long #define P 1000000007 #define re register #define N 1010 using namespace std; int a[N][N],b[N][N],c[N][N],d[N][N],e[N][N]; int n1,m1,n2,m2,n3,m3,ans=0; inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;} signed main() { // freopen("55.in","r",stdin); // freopen("55.out","w",stdout); n1=read();m1=read(); for(re int i=1;i<=n1;i++) for(re int j=1;j<=m1;j++) a[i][j]=read(); n2=read();m2=read(); for(re int i=1;i<=n2;i++) for(re int j=1;j<=m2;j++) b[i][j]=read(); n3=read();m3=read(); for(re int i=1;i<=n3;i++) for(re int j=1;j<=m3;j++) c[i][j]=read(); for(re int i=1;i<=n2;i++) for(re int k=1;k<=n3;k++) for(re int j=1;j<=m3;j++) d[i][j]=(d[i][j]+(b[i][k]*c[k][j])%P)%P; for(re int i=1;i<=n1;i++) for(re int k=1;k<=m1;k++) for(re int j=1;j<=m3;j++) e[i][j]=(e[i][j]+(a[i][k]*d[k][j])%P)%P; for(re int i=1;i<=n1;i++) for(re int j=1;j<=m3;j++) ans=(ans+e[i][j])%P; cout<<ans<<endl; return 0; } /* 2 2 1 1 1 1 2 3 1 1 1 1 1 1 3 2 1 1 1 1 1 1 80 */

T2

题面#

思路#

首先我们可以看到里面的40分是打个dij就可以水到的,但对于后面的点就没有这么好拿了。
本题需要用到状压我没学过只拿40很合理吧
状压什么东西呢,那当然是当前点的元素种数了,没学过也不要紧,其实挺好理解。
dis数组要开二维,第二维下标就是点的编号,第一维就是当前点的元素种类的值(这个东西下面简称为元素值),这么说也许不好理解,可以理解为最大为 271的一个值,他转化为二进制就是一个7位的数,如果当前位数上的值是一就是当前元素已经遍历过,反之则没有。
在遍历每一个点的时候,把当前点的元素值与(1<<(当前点的元素种类编号))进行|运算,这样你就会发现如果当前点没有遍历此元素的话,因为当前终点是此元素,就会标记成已经遍历;如果已经是遍历过的状态也就是是1的时候则不改变。
在最后的时候统计当前点的元素值转化成2进制的1的个数就可以知道遍历了多少元素了,然后取元素最多且距离尽量小的值就好了。

code#

Copy
#include<bits/stdc++.h> #define MAXM 200010 #define MAXN 10010 #define MAXS 1<<7 using namespace std; int n,m,dis[MAXS][MAXN],z[MAXN];//dis存放当前点元素种数的距离,z存放当前点的元素 int cnt,vis[MAXS][MAXN],head[MAXM];//vis标记当前点是入列,head链式前向星 struct sb{int w,v,next;}e[MAXM];//存边 inline void add(int u,int v,int w)//加边函数 { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } int main() { scanf("%d%d",&n,&m); for (int a=1;a<=n;a++) { char s[10]; scanf("%s",s);//"huo shui feng lei cao bing yan"; if (s[0]=='h') z[a]=0;//根据输入的字符串标记当前点的元素 else if (s[0]=='s') z[a]=1; else if (s[0]=='f') z[a]=2; else if (s[0]=='l') z[a]=3; else if (s[0]=='c') z[a]=4; else if (s[0]=='b') z[a]=5; else if (s[0]=='y') z[a]=6; } for(int a=1;a<=m;a++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w);//建无向图 add(v,u,w); } memset(dis,0x3f,sizeof dis); dis[1<<z[1]][1]=0;//赋初值 vis[1<<z[1]][1]=1;//当前点入列 queue<pair<int,int> >q;//建队列 q.push(make_pair(1<<z[1],1));//把当前点放入队列 while(!q.empty())//只要队列不空 { int ys=q.front().first;//取出元素数量 int u=q.front().second;//取出当前点的编号 q.pop();//弹出 vis[ys][u]=0;//标记当前点出列 for(int i=head[u];i;i=e[i].next)//枚举每一个与之相连的边 { int v=e[i].v;//取出终点 int w=dis[ys][u]+e[i].w;//计算当前点走到v的距离 int r=ys|(1<<z[v]);//当前点右移并取或,意思是如果没有到过当前颜色就标记遍历到当前颜色 if(w<dis[r][v])//松弛操作 { dis[r][v]=w; if(!vis[r][v])//如果不在队列里 { vis[r][v]=1;//标记入列 q.push(make_pair(r,v));//入列 } } } } int ans=0,res=0;//ans存放元素种数,res存放距离 for(int i=1;i<MAXS;i++)//开始遍历每一种情况 { if(dis[i][n]==0x3f3f3f3f)continue;//如果无法遍历到就直接跳过 int j=i,k=0;//j是当前点存颜色的值 while(j)//只要j大于0 { k+=j&1;//意思是如果这一位是1就j+1 j>>=1;//左移一位 } if(k>ans||(k==ans&&dis[i][n]<res))//如果种类数更多或者等量种类距离更少 { ans=k;//替换更新答案 res=dis[i][n]; } } printf("%d %d\n",ans,res);//输出 return 0;//好习惯 } /* 4 3 feng yan lei cao 1 2 2 2 3 10 2 4 2 */

T3

题面#

思路#

用线段树维护区间异或和,知识盲区咕咕咕。

code#

Copy
#include<bits/stdc++.h> #define bug cout<<"WTF?"<<'\n' #define rson mid+1,r,rt<<1|1 #define lson l,mid,rt<<1 #define P 1000000007 #define N 100010 using namespace std; int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;} int n,m; struct node { int l,r,cnt[32],col;//cnt存放异或的值,lr存放左右区间,col存放当前点的值 node()//初始化 { l=r=col=0; memset(cnt,0,sizeof(cnt)); } void color(int v)//更新异或的值 { col^=v;//更新异或值 for(int i=0,j=r-l+1;i<32;i++)//当前异或值的二进制最大位数 { if(v&1)cnt[i]=j-cnt[i]; v>>=1; } } int sum()//求异或和操作 { int ans=0,v=1; for (int i=0,j=r-l+1;i<32;i++) { ans=(ans+1ll*cnt[i]*(j-cnt[i])%P*v)%P; v=v<<1; if(v>=P)v-=P; } return ans; } }y[N<<2]; node operator+(const node &l,const node &r) { node ans; ans.l=l.l; ans.r=r.r; for(int i=0;i<32;i++) ans.cnt[i]=l.cnt[i]+r.cnt[i]; return ans; } void update(int rt){y[rt]=y[rt<<1]+y[rt<<1|1];} void push_col(int rt) { if (y[rt].col) { y[rt<<1].color(y[rt].col); y[rt<<1|1].color(y[rt].col); y[rt].col=0; } } void build(int l,int r,int rt) { // bug; if (l==r) { int v=read(); y[rt].l=y[rt].r=l; y[rt].color(v); return; } int mid=(l+r)>>1; build(lson); build(rson); update(rt); } void modify(int l,int r,int rt,int nowl,int nowr,int v) { if (nowl<=l&&r<=nowr){y[rt].color(v);return;} push_col(rt); int mid=(l+r)>>1; if (nowl<=mid) modify(lson,nowl,nowr,v); if (mid<nowr) modify(rson,nowl,nowr,v); update(rt); } node query(int l,int r,int rt,int nowl,int nowr) { if (nowl<=l && r<=nowr) return y[rt]; push_col(rt); int mid=(l+r)>>1; if (nowl<=mid) { if (mid<nowr) return query(lson,nowl,nowr)+query(rson,nowl,nowr); else return query(lson,nowl,nowr); } else return query(rson,nowl,nowr); } int main() { n=read();m=read(); build(1,n,1); for (int a=1;a<=m;a++) { int opt=read(); if (opt==1) { int l=read(),r=read(),v=read(); modify(1,n,1,l,r,v); } else { int l=read(),r=read(); printf("%d\n",query(1,n,1,l,r).sum()); } } return 0; } /* 3 3 1 2 3 2 1 3 1 1 3 3 2 1 3 */

T4

题面#

思路#

code#

Copy
#include<bits/stdc++.h> #define bug cout<<"WTF?"<<'\n' #define int long long #define N 110 using namespace std; int n,m,a[N],b[N],c[N],k,f[N][N];//abc存放礼包能获得的点券数,商品需要的点券和购买券,f是dp数组 int cnt[N],v[21][200010],ans;//cnt存放当前购买券的方案数,v表示当购买卷有i张时,当前第j中方案的点券数 void dfs1(int x,int sma,int smb)//当前第几个,点券数,购买券数 { if(x>k)//如果都选完了 { cnt[smb]++;//存放当前方案 v[smb][cnt[smb]]=sma; return ; } dfs1(x+1,sma+a[x],smb);//当前点选点券 dfs1(x+1,sma,smb+1);//当前点选购买券 return ; } int erfen(int i,int j) { int l=1,r=cnt[i]+1; while(l+1!=r) { int mid=(l+r)>>1; if(v[i][mid]<=j)l=mid; else r=mid; } if(v[i][l]>j)l--; return l; } void gent(int x,int cnt) { for(int i=0;i<=k;i++) { int pre=-1; for(int j=0;j<=m;j++) { int low; if(pre!=-1)low=pre; else low=erfen(i,f[j][i+cnt]-x-1); int up=erfen(i,f[j+1][i+cnt]-x-1); pre=up; ans+=(up-low)*j; if(f[j+1][i+cnt]>1e6)break; } } } void dfs2(int x,int sua,int sub) { if(x>n) { int d=ans; gent(sua,sub); return ; } dfs2(x+1,sua+a[x],sub); dfs2(x+1,sua,sub+1); return ; } signed main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++) cin>>b[i]>>c[i]; memset(f,0x3f,sizeof f); f[0][0]=0; for(int i=1;i<=m;i++) for(int j=m;j>=0;j--) for(int k=n;k>=0;k--) f[j+1][k+c[i]]=min(f[j+1][k+c[i]],f[j][k]+b[i]); for(int i=0;i<=m;i++) for(int j=1;j<=n+1;j++) f[i][j]=min(f[i][j],f[i][j-1]); k=n/2; dfs1(1,0,0); for(int i=0;i<=k;i++) sort(v[i]+1,v[i]+cnt[i]+1); dfs2(k+1,0,0); cout<<ans<<endl; return 0; } /* 2 2 1 2 0 1 3 0 */
posted @   北烛青澜  阅读(23)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
目录