链目链接:合法数对
分析:
首先,数据范围非常大,要么就是高精度,要么就是字符串存储
本题输入以二进制的形式给出。
对于没有思路的小伙伴,大家可以打表,找找规律
那这道题,我是用dp做的
x^y=x|y,即二进制对应位,x与y不同时为1
打表如下
十进制值 | 对应答案 | 二进制 |
---|---|---|
1 | 3 | 1 |
2 | 7 | 10 |
3 | 9 | 11 |
4 | 17 | 100 |
5 | 21 | 101 |
6 | 25 | 110 |
7 | 27 | 111 |
8 | 43 | 1000 |
9 | 51 | 1001 |
10 | 59 | 1010 |
11 | 63 | 1011 |
12 | 71 | 1100 |
13 | 75 | 1101 |
14 | 79 | 1110 |
15 | 81 | 1111 |
16 | 113 | 10000 |
对于找规律的people来说:
首先看对于1000(2)和1001(2)来说:
前面三位是相同的,都是100,那么是否可以由100来推出1001?
经过观察不难发现,每次在前一个二进制数字后,多加一个1,对应答案就会×3
每次加上一个0,对应答案就是,设cnt=1000里面0的个数,则答案为100(2)之后放1的答案,减去2cnt次方
从dp角度观察,在1000内,x取值[0,8],y取值[0,8],
1001比1000多了一个1,x取值[0,9],y取值[0,9],
即多了x取9,y取[0,9],y取9,x取[0,9],这么多情况,当然,其中很多种都是无效的,
那么哪些是有效的呢,当x取9的时候,假设1001,对应四个位置,1234,
那么取3、4,这两个位置,都不会形成1的交集,即2²(每个位置都有0、1两种情况,即2*2),
同理,反过来y取9也是同样的,即,1001的对应答案 - 23
代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N=2e6+10,mod=998244353;
int n,m,f[N][2],cnt;//前i位,以j结尾的答案的个数(当然可以滚动数组优化掉一维啦,本代码直接
string s; // 去掉前面一维就可以了,这里两维更好看懂)(ps:指不经过大脑)
int qmi(int a,int b)//快速幂
{
int 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);//快输
cin>>s;
n=s.size();
f[0][1]=3;//特殊定义前1位以1结尾答案为3,字符串下标从0~n-1,所以这里是0
for(int i=1;i<n;i++)
{
f[i][1]=f[i-1][s[i-1]-'0']*3%mod;//前i位以1结尾,等于前i-1位以s[i-1]结尾的答案×3
if(s[i]=='0') cnt++,f[i][0]=(f[i][1]-qmi(2,cnt)+mod)%mod;
} // 记录0的个数,前i位以0结尾,等于前i位以1结尾的答案减去2的cnt次方,
cout<<f[n-1][s[n-1]-'0']<<endl; //这里要加上mod,防止负数
return 0;//输出!!!0^0 // s[i-1]-'0':字符转化为整数
}