//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2022.10.7模拟赛

T1

题面

思路

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

code

#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数组要开二维,第二维下标就是点的编号,第一维就是当前点的元素种类的值(这个东西下面简称为元素值),这么说也许不好理解,可以理解为最大为 \(2^{7}-1\)的一个值,他转化为二进制就是一个7位的数,如果当前位数上的值是一就是当前元素已经遍历过,反之则没有。
在遍历每一个点的时候,把当前点的元素值与(1<<(当前点的元素种类编号))进行|运算,这样你就会发现如果当前点没有遍历此元素的话,因为当前终点是此元素,就会标记成已经遍历;如果已经是遍历过的状态也就是是1的时候则不改变。
在最后的时候统计当前点的元素值转化成2进制的1的个数就可以知道遍历了多少元素了,然后取元素最多且距离尽量小的值就好了。

code

#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

#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

#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 @ 2022-10-07 22:17  北烛青澜  阅读(29)  评论(0)    收藏  举报