5.25 费解的开关

 

 

 

思路,枚举

开关按下两次就复原,所以一个开关只有两种情况,按下和不按下,5*5的开关,一共25个开关,一共有2^25种情况,for (int i = 0;i < 2^25;i++)进行操作,计算按下开关次数,若大于6,则跳过,否则,进行计算,判断按下后是否符合要求,符合则更新需要的最小次数,否则不更新。最后,如果最小次数大于6输出-1,否则输出最小次数。

考虑,第一行开关状态固定,能够影响到第一行的只有第二行,其他行无法影响第一行,所以,对于第一行中的第k列,如果第k列是不亮的,为了使该灯变亮,需要第二行的第k列按钮按下;这将确定第二行的所有开关的按下/不按的操作,第二行的灯状态将确定(如果再按下第二行的开关,第一行的第k列灯将会再次不亮);第三行的开关操作由第二行的灯的状态确定,第四行的开关操作由第三行的灯的状态确定,第五行的操作由第四行的灯的状态确定,第五行是最后一行,到达枚举的终点,如果第五行的灯都是亮的,说明当前枚举的开关操作是合理的,记录开关操作次数,否则说明当前枚举的开关操作不能使灯全部都亮,操作不满足要求, 更新需要的最少的开关的操作次数。最后,如果2^5种情况得到的最小开关操作次数大于6,则输出-1,否则输出操作次数。(根据这个可以提前判断,枚举每一种开关操作时,大于6则继续下一次操作,不更新最少开关次数)注意,要取min的,数组,则初始化为0x3f,memset,按字节填充,两倍不超int数据类型最大范围;数字,非常大的一个数,比如1<<32;。

过程如下:

枚举第一行开关的2^5种操作可能情况,确定第一行的灯的状态,更新开关操作次数times,

        为了使1-4行灯是亮的,确定2-5行开关的操作,更新开关操作次数times,如果times大于6,直接进入下一种情况讨论continue;,

        如果第五行的灯都是亮的,说明当前枚举的开关操作是合理的,记录开关操作次数,更行最小开关操作次数min_times

                否则说明当前枚举的开关操作不能使灯全部都亮,操作不满足要求

        如果min_times大于6,则输出-1,否则输出min_times。

代码如下

#include<iostream>

using namespace std;
const int N=6;
int n;
char m[N];
int led[N][N];
int copy1[N][N];
int dx[5]={-1,1,0,0,0},dy[5]={0,0,0,-1,1};
void print(int a[N][N]){
	for(int i = 0;i < 5;i++){
		for(int j = 0;j < 5;j++)
			cout<<a[i][j]<<" ";
		cout<<endl;
	}
}
void copy_f(int a[N][N],int b[N][N]){
	for(int i = 0;i < 5;i++)
		for(int j = 0;j < 5;j++)
		a[i][j]=b[i][j];
}

void change(int x,int y){
	for(int i = 0;i < 5;i++)
		{
			int nx=x+dx[i],ny=y+dy[i];
			if(nx>=0&&nx<=4&&ny>=0&&ny<=4)
				if(copy1[nx][ny]==1)copy1[nx][ny]=0;
				else copy1[nx][ny]=1;
		}
}

void work(){
	int times,min_times=1<<30; //
	for(int state = 0;state < 1<<5;state++) {
		times=0;
		copy_f(copy1,led);//复制 ,下面的操作基于copy数组,不改变led数组 
		for(int i = 0;i < 5;i++)//第一行 
			if(state>>i &1){//开关操作 
				change(0,4-i);
				times++;
			}
		for(int i = 0;i < 4;i++)//根据0-3行确定1-4行操作 
			for(int j = 0; j < 5;j++)
				if(copy1[i][j]==0){
					change(i+1,j);
					times++;
				} 	
		bool flag=true;
		for(int i = 0;i < 5;i++)
			if(copy1[4][i]==0)
			{
				flag=false;
				break;
			}
		if(flag)min_times=min(min_times,times); 
	}
	
	if(min_times<=6)cout<<min_times<<endl;
	else cout<<-1<<endl;
}

int main(){
	cin>>n;
	while(n--){
		for(int i = 0;i < 5;i++){
			cin>>m;
			for(int j = 0;j < 5;j++)
				//cout<<m[j]<<" ";
				if(m[j]=='1')led[i][j]=1;
				else led[i][j]=0;
		}
		work();	
	}
	return 0;
}

第一个小错误:change(0,4-i);写为change(0,i);,实际上不影响。

改了半天才发现的小错误:

int nx=x+dx[i],ny=y+dy[i];  误写为int nx=x+dx[i],ny=y+dx[i];

约数之和

数的质因数表示,约数个数之和, 约数之和,

代码

#include<bits/stdc++.h>
using namespace std;
const int mod=9901;
int qmi(int m,int k){//logk
	//m^k % mod
	long long res=1;
	m=m%mod;
	while(k){
		if(k&1)res*=m%mod;
		res%=mod;
		m=m*m%mod;
		k>>=1;
	}
	return (int)res;
}
int sum(int p,int k){
	if(k==0)return 1;
	//if(k%2==0)return (p%mod*sum(p,k-1)+1)%mod;
	if(k%2==0)return ((1+qmi(p,(k-1)/2+1))*sum(p,(k-1)/2)%mod+qmi(p,k))%mod;
	return (1+qmi(p,k/2+1))*sum(p,k/2)%mod;
}
int main(){
	
	int A,B;
	cin>>A>>B;
	int res=1;
	for(int i = 2;i <=A;i++){
		int s=0;//i^s 
		while(A%i==0){
			s++;
			A/=i;
		}
		//cout<<"s="<<s<<" "<<endl;
		if(s)res=res*sum(i,s*B)%mod;
	}
	if(!A)res=0;
	cout<<res<<endl;
	
	//cout<<qmi(7,3);
	return 0;
}

我的qmi模板,见5.24 基础题目_wxxka的博客-CSDN博客

#include<bits/stdc++.h>
using namespace std;
const int mod=9901;
int qmi(int a,int b){
    int p = mod;
    long long res = 1,ci=1;
    int flag=0;
    if(b==0){
            res%=p;
        }
    else{
        while(b){
    	if (flag==0)ci=a%p;
    	else
          ci=(ci%p)*(ci%p)%p;
        
		if (b&1)res=(res*(ci%p))%p;
        b>>=1;
        flag++;
        //cout<<ci<<"  "<<res<<endl;
    }
    }
    return res;
}
int sum(int p,int k){
	if(k==0)return 1;
	//if(k%2==0)return (p%mod*sum(p,k-1)+1)%mod;
	if(k%2==0)return ((1+qmi(p,(k-1)/2+1))*sum(p,(k-1)/2)%mod+qmi(p,k))%mod;
	return (1+qmi(p,k/2+1))*sum(p,k/2)%mod;
}
int main(){
	
	int A,B;
	cin>>A>>B;
	int res=1;
	for(int i = 2;i <=A;i++){
		int s=0;//i^s 
		while(A%i==0){
			s++;
			A/=i;
		}
		//cout<<"s="<<s<<" "<<endl;
		if(s)res=res*sum(i,s*B)%mod;
	}
	if(!A)res=0;
	cout<<res<<endl;
	
	//cout<<qmi(7,3);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值