签到题,n!=m就No,我简单证明一下,如果n为奇数,每次翻转硬币,正面朝上的贡献都是偶数次,永远也不可能,如果n为偶数,那么我翻转一枚硬币,现有的正面朝上的数量是奇数,但是Alice每次翻转贡献是偶数次,所以也不可能。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int T,n,m;
cin>>T;
while(T--)
{
cin>>n>>m;
if(n==m)puts("Yes");
else puts("No");
}
}
设d[ i ][ j ]为第 i 个回合时,数字变成 j 的方案数,转移很简单,d[ i ][ j ]=d[ i-1 ][ -j ]+d[ i-1 ][ j-a[ i ] ],但是面临着下标为负数的情况,因此把所有数字都加上666*300,即666*300代表数字0,然后就水题了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=666*2*300+10,mod=1e8+7,N=666*300;
ll d[2][maxn];
int a[305],cur,n;
void add(ll& x,ll y)
{
x=(x+y)%mod;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];d[0][N]=1;
for(int i=1;i<=n;i++)
{
cur=!cur;
for(int j=0;j<maxn;j++)d[cur][j]=0;
for(int j=0;j<maxn;j++)
if(d[!cur][j])
{
add(d[cur][j+a[i]],d[!cur][j]);
add(d[cur][2*N-j],d[!cur][j]);
}
d[cur][N+666]=0;
}
cout<<d[cur][N-666];
}
带权并查集 ,用并查集把联通块联通起来并算出联通快的总权值即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int to[maxn],p[maxn],vis[maxn],cnt;
ll d[maxn],res[maxn],ans;
int find(int u)
{
if(p[u]!=u)
p[u]=find(p[u]);
return p[u];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&d[i]),p[i]=i;
for(int i=1;i<=n;i++)
{
scanf("%d",&to[i]);
int fa=find(i),fb=find(to[i]);
if(fa!=fb)
{
p[fa]=fb;
d[fb]+=d[fa];
}
}
for(int i=1;i<=n;i++)
{
int fa=find(i);
if(!vis[fa])
{
res[++cnt]=d[fa];
vis[fa]=1;
}
}
sort(res+1,res+1+cnt);
for(int i=cnt;i;i--)
{
ans+=res[i];
if(cnt-i+1==m)break;
}
printf("%lld\n",ans);
}
这个题很多人用fwt,我不会,看到有大佬用最短路过了这个题,真是学到了 orz
思路:设d[ i ]为状态初始的 n 个状态 异或 i 后,所能得到最少的1的个数,那么设初始的 n 个状态的d[ s ]=0,然后进队,跑最短路即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e6+10;
int d[maxn],ans=20,n,m;
char s[30];
queue<int>q;
int main()
{
cin>>n>>m;
for(int i=0;i<(1<<m);i++)d[i]=m;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
int x=0;
for(int j=0;j<m;j++)
if(s[j]=='1')x|=(1<<j);
d[x]=0;
q.push(x);
}
while(!q.empty())
{
int u=q.front();q.pop();
for(int j=0;j<m;j++)
{
int v=(u^(1<<j));
if(d[v]>d[u]+1)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
for(int i=0;i<(1<<m);i++)
ans=min(ans,m-d[i]);
cout<<ans;
}
ccpc camp有一个题是求球题的体积交,把那个题的解法稍微改改就行,不贴代码了,