Atcoder356
C
解题思路
- 先从数据量上看,\(2^{15}\)=32768,那么时间复杂度为O(\(2^{n}*m*n\))大约在\(4*10^{7}\)左右,可以直接跑暴力枚举。
- 按照正常思路,我们需要创建一个二维数组来存储测试中的数据。然后再创建一个一维数组来模拟n把钥匙的选和不选。这样暴力枚举上的对照比较麻烦。依照题意,选和不选可以用1和0表示。那么n把钥匙的所有情况就是一个二进制数从零开始到n-1的遍历。既然枚举的数可以用数字表示,那么测试数据的数也可以用同样的方式进行压缩成一个数,数组就可以压缩成一维来存储测试中的数据。
- 那么该如何对照测试和枚举的数呢?首先,我们先明确正确的钥匙个数是数据的二进制中1的个数(这里可以用__builtin_popcount()实现),那么按照题意,我们要验证枚举数在测试中的结果,即按照枚举的情况在测试中的开门数是否大于k,通过举例,假如在二进制中某一位的门要是开的,那么需要测试和枚举的数据在二进制的同一位中要同时为1,那么就可以用位运算(&)来验证开的门的个数。
#include <bits/stdc++.h>
#define debug1(X) std::cout << #X << ": " << X << '\n'
#define debug2(X) std::cout << #X << ": " << X << ' '
using i64 = long long;
void solve()
{
int n,m,k;
std::cin>>n>>m>>k;
std::vector<int>a(m);
std::vector<char>ok(m);
int ans=0;
for(int i=0;i<m;i++){
int c;
std::cin>>c;
for(int j=0;j<c;j++){
int x;
std::cin>>x;
x--;
a[i]+=(1<<x);
}
std::cin>>ok[i];
}
for(int i=0;i<(1<<(n));i++){
bool jub=true;
for(int j=0;j<m;j++){
int cnt=__builtin_popcount(i&a[j]);
if(cnt>=k&&ok[j]=='x'){
jub=false;
break;
}
if(cnt<k&&ok[j]=='o'){
jub=false;
break;
}
}
if(jub){
ans++;
}
}
std::cout<<ans<<"\n";
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
// std::cin >> t;
while (t--)
{
solve();
}
return 0;
}
D
题意大致就是求m在二进制中每一位上1在1~n中出现的次数之和。
那如何求某一位上1在1~n之前出现过的次数呢?
我们知道某一位(n)1出现从1~\(2^n\)次数为\(2^{n-1}\).
- 例如100这个二进制数从右到左第三位出现的次数从001到100为\(2^2\).
那么我们就可以因此将某一个二进制数拆分为两个部分。
举个例子,求100100的从右到左第三位为1在1~100100出现的次数,我们就将100100分为左边100,右边100.
那么我们可以简单知道右边100出现的次数应该是\(2^2\),而左边则是[0,100)共8个数,就是100可以看成0100,那么从0100到100100中间有0到100(即8个数)的右边100出现次数。所以总的次数就是左边的数。
那如果100100变为100111呢?
按照上述条件再来判断就会发现,我们只判断到了1100100的情况,那么再100100100111的情况就要另作边界判断,也很简单,就是右边111~100的个数再加上就行。
#include <bits/stdc++.h>
#define debug1(X) std::cout << #X << ": " << X << '\n'
#define debug2(X) std::cout << #X << ": " << X << ' '
using LL = long long;
void solve()
{
LL ans=0;
LL mod=998244353;
LL n,m;
std::cin>>n>>m;
for(int i=0;i<60;i++){
if((m>>i)&1){
LL w=1LL<<i;
ans+=n/(w*2)*w+std::max(0LL,n%(2*w)-w+1);
}
ans%=mod;
}
std::cout<<ans<<"\n";
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
// std::cin >> t;
while (t--)
{
solve();
}
return 0;
}