A.知识点:博弈论
题解思路:
第一种情况,n=m,显然“Yes”
第二种情况,n!=m;把n分为就奇偶两种情况:(1)n为奇数,要将所有硬币全部变成反面,等价于所有的回合数翻硬币的次数之和是奇数,那么即使Bob什么都不做,Alice无论怎么做,都不会达到目的 (2)n为偶数,等价于总数和为偶数,那么,Alice有可能完成,这时候,Bob只要在第一次把任意一个硬币翻过来,这个时候的情况就和(1)一样了。
所以,n=m,yes
n!=m,no
B.知识点:动态规划
dp[i][j]表示在第i个回合,构成数字i的情况数。
由此,状态转移方程就是:dp[i] [j] = dp[i-1] [j-a[i] ] +dp[i-1] [-j]
注意要加两个东西:
(1):滚动数组 (二维存不下)
(2)排除所有j="666"的情况
由于j和-j以及j-a[i]的正负的不确定性,只用一个dp数组滚动肯定不行,因此要加上一个辅助数组来保存上一个回合dp值
code如下:
#include<bits/stdc++.h>
#define register int rint
#define INF 0x3f3f3f3f3f
#define MOD 100000007
#define mem(a,b) memset(a,b,sizeof(a))
#define PI 3.141592653589793
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=400000;
const int Max=1e4+20;
const double esp=1e-8;
inline int rd() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n,a[N],dp[N+200],tmp[N+200];
int main()
{
n=rd();
for(int i=1;i<=n;++i) a[i]=rd();
mem(dp,0);
dp[199800]=1;
for(int i=1;i<=n;++i)
{
mem(tmp,0);
for(int j=0;j<=399600;++j)
{
int real=j-199800;
if(real==666) continue;
tmp[j]=(dp[399600-j]+tmp[j])%MOD;
tmp[j]=(dp[j-a[i]]+tmp[j])%MOD;
}
//cout<<tmp[19934]<<' '<<tmp[199467]<<' '<<tmp[199800]<<' '<<tmp[200133]<<' '<<tmp[200466]<<endl;
memcpy(dp,tmp,sizeof(tmp));
}
cout<<dp[199134]<<endl;
//cout<<dp[1][n][666]<<endl;
}
C.知识点:并查集
1.把所有节点变成并查集森林
2.把每一棵树的a【i】总和求出+排序
3.加和前m个,即为所求
D.知识点:思维+bfs
题解思路:有n个数,每个数m位,那么最多有2^m种情况,每一种遍历再和n个数异或的话,时间复杂度就是n*2^m,太大了。
让我们换一种思路来看,把每一位是0还是1看成一种状态,那么就有m种状态,现在把这m个位想象成一个图,起点是数字x,终点可能是(1111...)m个1(可能不到)。那么我们每次改变一个位,然后标记我们走过的路径的长度,这样就类似于bfs的做法(一边标记,一边拓展)。最总我们用这n个数能走过的最大路径长度*-1+m就是答案了。
code(来自官方题解:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=40380369)
#include<bits/stdc++.h>
using namespace std;
int deep[1<<22];
void solve(){
queue<int> q;
int n,m,ans=0;
char s[30];
scanf("%d %d",&n,&m);
memset(deep,-1,sizeof(int)*(1<<(m+1)));
for(int i=0;i<n;i++){
scanf("%s",s);
int f=0;
for(int j=0;j<m;j++){
f+=(1<<j)*(s[j]-'0');
}
if(deep[f]==-1) {
deep[f]=0;
q.push(f);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
ans=max(ans,deep[u]);
for(int i=0;i<m;i++){
if(deep[u^(1<<i)]==-1){
deep[u^(1<<i)]=deep[u]+1;
q.push(u^(1<<i));
}
}
}
printf("%d\n",m-ans);
}
int main()
{
solve();
return 0;
}