文章目录
- 4+题单
- A - [有趣的数](https://www.acwing.com/problem/content/description/3198/)
- B - [取数游戏 II](https://www.luogu.com.cn/problem/P1288)
- C - [acwing-nim](https://www.acwing.com/problem/content/submission/code_detail/29453954/)
- D - [排列计数](https://www.acwing.com/problem/content/description/232/)
4+题单
A - 有趣的数
动态规划的时候出过一次,在n-1位中先选j个2,剩下的n-j个数的位子全部放剩下的两个数,其中j个数中的第一位一定是2,剩下的j-1位就有j-1种选择也就是,反正最后有个3兜底,剩下的你n-j个数也一样,留一位兜底,那么0就有n-j-1种位置可以选
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1000000007,N=1e3+10;
ll c[N][N];
signed main()
{
int n;
cin>>n;
//预处理出组合数
for(int i=0;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
if(!j) c[i][j]=1;
else
c[i][j]=(c[i-1][j]%mod+c[i-1][j-1]%mod);
}
}
//在n-1个位置种选
ll res=0;
for(int i=2;i<=n-2;i++)
{
res=(res+c[n-1][i]*(i-1)*(n-i-1))%mod;
}
cout<<res<<endl;
return 0;
}
B - 取数游戏 II
博弈论了.
初步想法是能够同时在左右两条边都为0的起点就都不能赢。否则先出发的在选择起点的时候一定是0边的左右任意一条边都能赢
两个人是同一个起点
#include<bits/stdc++.h>
using namespace std;
const int N=22;
int a[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i+1<=n;i++)
{
if(a[i]==a[i+1]&&!a[i])
{
puts("NO");
return 0;
}
}
puts("YES");
return 0;
}
洛谷题解后
#include<bits/stdc++.h>
using namespace std;
const int N=25;
int a[N];
signed main()
{
int n;
cin>>n;
//为什么一定要先读入,不先读入,测试点8过不了
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
if(a[i]==0)
{
if(i%2==0)
{
puts("YES");
return 0;
}
break;
}
}
for(int i=n;i>=1;i--)
{
if(a[i]==0)
{
if((n-i+1)%2==0)
{
puts("YES");
return 0;
}
break;
}
}
puts("NO");
return 0;
}
C - acwing-nim
如果所有数异或之后是不为0的数x,那么一定存在一个数 a i a_i ai能满足使x的最高位为1,那么让 a i a_i ai与x异或,再用 a i a_i ai减,就可以会等于,一定会有剩下 a i − ( a i − ( a i ∣ x ) ) a_i-(a_i-(a_i|x)) ai−(ai−(ai∣x))和原来所有数异或之后的值相等,那么原本先手拿走的 a i ∣ x a_i|x ai∣x这么多的石头,会让剩下的所有数异或起来是0,这样就能够达到先手先出手就赢的状态
#include<iostream>
#include<cstring>
using namespace std;
int main() {
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
int res = 0;
while (n--) {
int x;
cin >> x;
res ^= x;
}
if (res) puts("YES");
else puts("NO");
}
return 0;
}
D - 排列计数
感觉还是要用到组合数,在n个里面固定m个,剩下(n-m)个排列组合减去他们也等于i的可能性
#include<bits/stc++.h>
using namespace std;
const int mod=1e9+7,N=1e6+5;
int c[N][N];
int fact[N],infact[N];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
scanf("%d",&t);
for(int i=0;i<=N;i++)
{
for(int j=0;j<=i;j++)
{
if(!j) c[i][j]=1;
else c[i][j]=c[i-1][j]%mod+c[i-1][j-1]%mod;
}
}
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=1;)
}
return 0;
}
优质题解
正解,是组合数乘上错排,
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+7,N=1e6+10;
ll f[N];
ll fact[N],infact[N];
ll qui(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
scanf("%d",&t);
fact[0]=fact[1]=infact[0]=infact[1]=1;
f[0]=1;
f[1]=0;
f[2]=1;
fact[2]=2;
infact[2]=qui(fact[2],mod-2)%mod;
for(int i=3;i<=N;i++)
{
f[i]=(f[i-1]+f[i-2])%mod*(i-1)%mod;
fact[i]=fact[i-1]*i%mod;
infact[i]=qui(fact[i],mod-2);
}
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",(fact[n]*infact[n-m]%mod*infact[m]%mod*f[n-m]%mod));
}
return 0;
}