洛谷刷题7.7

P2622 关灯问题 II - 洛谷

本质是bfs求最短路,通常我们的状态是一个点,现在我们的状态是01数组,我们可以将它转换成十进制来简便的表示状态,但是状态转移时要熟悉位运算。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
int arr[101][11];
int n,m,step[1025]; 
queue<int>q;
bool wei(int x,int y){
	x >>= y;
	return x&1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
	for(int j=0;j<n;j++)
		cin>>arr[i][j];
q.push((1<<n)-1);//全开 
step[(1<<n)-1] = 1;
while(!q.empty()){
	int now = q.front();
	q.pop(); 
	if(now == 0){
		cout<<step[0]-1;
		return 0;
	}
	for(int i=1;i<=m;i++){
		int temp =now;
		for(int j=0;j<n;j++){
			if(arr[i][j] == 1 && wei(temp,j)) temp ^= (1<<j);
			else if(arr[i][j] == -1 && !wei(temp,j)) temp |= (1<<j);
		}
		if(step[temp] == 0){
			step[temp] = step[now] + 1;
			q.push(temp);
		}
	}
}
cout<<-1;
	return 0;
}

P1336 最佳课题选择 - 洛谷

简单的部分背包

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll dp[205],n,m,a,b; 
int main()
{
cin>>n>>m;
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
while(m--){
	cin>>a>>b;
	for(int i=n;i>=1;i--){
		for(int j=0;j<=i;j++){
			dp[i]=min(dp[i],dp[i-j]+a*(ll)pow(j,b));
		}
	}
}
cout<<dp[n];
	return 0;
}

P1474 [USACO2.3] Money System / [USACO07OCT]Cow Cash G - 洛谷

简单的完全背包求方案数

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll n,v,dp[10005],a;
int main()
{
cin>>v>>n;
dp[0]=1;
while(v--){
	cin>>a;
	for(int i=a;i<=n;i++) dp[i]+=dp[i-a];
}
cout<<dp[n];
	return 0;
}

P1077 [NOIP 2012 普及组] 摆花 - 洛谷

简单的01背包求方案数

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll n,m,dp[10005],a,mod=1000007;
int main()
{
cin>>n>>m;
dp[0]=1;
while(n--){
	cin>>a;
	for(int i=m;i>=0;i--){
		for(int j=1;j<=min(i,(int)a);j++){
			dp[i]+=dp[i-j];
			dp[i]%=mod;
		}
	}
}
cout<<dp[m];
	return 0;
}

P1141 01迷宫 - 洛谷

这题有个优化小技巧,记录哪个点是在哪个时间访问的,再通过这个时间去映射到块的大小。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
int n,m,ans[1005][1005],v[100005],sum,a,b,now=1;
char arr[1005][1005];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
void bfs(int sx,int sy,int num){
	sum=1;
	queue<pair<int,int> >r;
	r.push(make_pair(sx,sy));
	ans[sx][sy]=num;
	while(!r.empty()){
		int x = r.front().first,y = r.front().second;
		r.pop();
		for(int i=0;i<4;i++){
			if(x+dx[i]>=1&&x+dx[i]<=n&&y+dy[i]>=1&&y+dy[i]<=n){
				if(arr[x][y]!=arr[x+dx[i]][y+dy[i]]&&ans[x+dx[i]][y+dy[i]]==0){
					ans[x+dx[i]][y+dy[i]]=num;
					sum++;
					r.push(make_pair(x+dx[i],y+dy[i]));
				}
			}
		}
	}
	v[num]=sum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cin>>arr[i][j];
while(m--){
	cin>>a>>b;
	if(ans[a][b]) cout<<v[ans[a][b]]<<endl;
	else{
		bfs(a,b,now++);
		cout<<v[ans[a][b]]<<endl;
	}
}
	return 0;
}

P8673 [蓝桥杯 2018 国 C] 迷宫与陷阱 - 洛谷

广搜,注意记录该点是否访问是要记录该点的坐标和剩余无敌的步数。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
struct point{
	int x,y,t,step;//无敌时间 
};
int n,k,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
char arr[1005][1005];
bool vis[1005][1005][11];//第三维是时间 
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cin>>arr[i][j];
queue<point>r;
r.push(point{1,1,0,0});
while(!r.empty()){
	int x=r.front().x,y=r.front().y,t=r.front().t,s=r.front().step;
	if(x==n&&y==n){
		cout<<s;
		return 0;
	}
	r.pop();
	for(int i=0;i<4;i++){
		if(x+dx[i]>=1&&x+dx[i]<=n&&y+dy[i]>=1&&y+dy[i]<=n){
			if(arr[x+dx[i]][y+dy[i]]=='.'||(arr[x+dx[i]][y+dy[i]]=='X'&&t>0)){
				if(!vis[x+dx[i]][y+dy[i]][max(t-1,0)]){
					r.push(point{x+dx[i],y+dy[i],max(t-1,0),s+1});
					vis[x+dx[i]][y+dy[i]][max(t-1,0)]=true;
				}				
			}
			if(arr[x+dx[i]][y+dy[i]]=='%'){
				arr[x+dx[i]][y+dy[i]]='.';
				r.push(point{x+dx[i],y+dy[i],k,s+1});
				vis[x+dx[i]][y+dy[i]][k]=true;
			}
		}
	}
}
cout<<-1;
	return 0;
}

P12323 [蓝桥杯 2023 省 Java B] 阶乘求和 - 洛谷

注意该题只取后9位,当i>=40时,40!,41!后9位都是0,所以只用循环到39.

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll ans=0,now=1,mod=1000000000;
int main()
{
for(ll i =1;i<=40;i++){
//	now *= (i%mod);
	now *= i;
	now %= mod;
	ans += now;
	ans %= mod;
}
cout<<ans;
	return 0;
}