思路:全排列减去单峰排列即为答案。
单峰排列即:峰左边下标的左边没有比它大的,峰右边的下标的右边没有比它大的。
单峰排列个数: 2 n − 1 2^{n-1} 2n−1,除 n n n外每个数可在左侧或右侧。
#include
using namespace std;
typedef long long ll;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first
#define se second
#define pb push_back
#define il inline
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main(){
int n;
scanf("%d",&n);ll x=1;
for(int i=1;i<=n;i++) x=x*i%mod;
printf("%lld\n",((x-ksm(2,n-1))%mod+mod)%mod);
return 0;
}
思路:结论:
1. n > 3 1.n>3 1.n>3无解,因为 4 × 4 4\times 4 4×4矩阵的 4 4 4个 2 × 2 2\times 2 2×2矩阵和不满足。
2. n = 1 , a n s = 0 2.n=1,ans=0 2.n=1,ans=0
所以只需考虑 n = 2 , 3 n=2,3 n=2,3的情况,暴力枚举第一列第二列,第二列和第三列的答案情况,取最小值即可。
#include
using namespace std;
typedef long long ll;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first
#define se second
#define pb push_back
#define il inline
#define IOS ios::sync_with_stdio(false),cin.tie(0)
int main(){
IOS;
int n,m;
cin>>n>>m;
vector<vector<int> >a(n,vector<int>(m));
string s;
for(int i=0;i<n;i++){
cin>>s;
for(int j=0;j<m;j++) a[i][j]=s[j]-'0';
}
if(n>3) return cout<<-1<<endl,0;
if(n==1) return cout<<0<<endl,0;
int ans=n*m;
for(int x=0;x<2;x++)
for(int y=0;y<2;y++){
int tmp=0;
for(int j=0;j<m;j++){
int s1=(a[0][j]+a[1][j])%2,c=(x+j)%2;//第一列和第二列.
if(s1!=c) tmp++;
if(n==3){
int s2=(a[1][j]+a[2][j])%2,d=(y+j)%2;//第二列和第三列
if(s2!=d&&s1==c) tmp++;//若两个都需要改,则只需改中间的格子,上面已经加过一次.
}
}
if(ans>tmp) ans=tmp;
}
cout<<ans<<endl;;
return 0;
}