多校A层冲刺NOIP2024模拟赛04
A. 02表示法
对要求的数二进制拆分,每一位递归求解,大于2就继续拆,是1返回 \(2(0)\) ,是2返回 \(2\),由于外层的数比较大,所以
要写一个高精除低精
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int maxn=1e5+10;
using namespace std;
int n,ans[maxn],top;
string s,t;
void pre(string s)
{
s=" "+s;
t=" "+t;
while(s[1]-'0'>0||s.size()>1)
{
int len=s.size()-1,x=0,cnt=0,i;
for(i=1;i<=len&&s[i]=='0';i++);
for(;i<=len;i++)
{
x=x*10+s[i]-'0';
int z=x/2;
t=t+(char)(z+'0');
x=x-(t[++cnt]-'0')*2;
}
// cout<<s<<endl;
s=t;t=" ";
ans[++top]=x;
}
}
void lsx(int x)
{
if(x>1)
{
int cnt=0;
for(int i=62;i>=0;i--) if((1ll<<i)&x) cnt++;
cout<<2<<"(";
for(int i=62;i>=0;i--)
{
if((1ll<<i)&x)
{
lsx(i);
if(--cnt) cout<<"+";
}
}
cout<<")";
}
else
{
if(x==1)cout<<2;
else cout<<"2(0)";
return ;
}
}
signed main()
{
freopen("pow.in","r",stdin);
freopen("pow.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>s;
pre(s);
int i,temp,sum=0;
for(i=top;i>=1&&ans[i]==0;i--);temp=i;
for(i=temp;i>=1;i--) if(ans[i]==1)sum++;
for(i=temp;i>=1;i--)
{
if(ans[i]==1)
{
lsx(i-1);
if(--sum) cout<<"+";
}
}
return 0;
}
/*
261770307610118667978710393358
*/
B. 子串的子串
由于子串中有重复的,我们假设有两个相邻的重复字串 \(s1(l1,r1),s2(l2,r2)\),所以我们枚举长度,再枚举左端点,对每一个
相邻的重复子串的 \(l1-r2\) 减一,再用二维前缀和求出每个区间的答案,这样就相当于对于每一对相邻的重复子串,把靠后的那
个删掉,只保留第一个,这样不管后面是否有重复字串,加进来一个影响就消掉一个。
点击查看代码
#include<bits/stdc++.h>
#define int unsigned long long
const int base=133;
const int maxn=3010;
using namespace std;
int n,q,ha[maxn],po[maxn],ans[maxn][maxn];
string s;
unordered_map<int,int>mp;
int jie(int l,int r)
{
return ha[r]-ha[l-1]*po[r-l+1];
}
signed main()
{
freopen("substring.in","r",stdin);
freopen("substring.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
cin>>s;s=" "+s;
po[0]=1;
for(int i=1;i<=n;i++)ha[i]=ha[i-1]*base+s[i],po[i]=po[i-1]*base;
for(int len=1;len<=n;len++)
{
mp.clear();
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;
int tem=jie(l,r);
ans[mp[tem]][r]--;
mp[tem]=l;
}
}
for(int l=n;l>=1;l--)
{
for(int r=l;r<=n;r++)
{
ans[l][r]+=ans[l+1][r]+ans[l][r-1]-ans[l+1][r-1]+1;
}
}
for(int i=1;i<=q;i++)
{
int x,y;
cin>>x>>y;
cout<<ans[x][y]<<'\n';
}
return 0;
}
/*
*/
C. 魔法咒语
题解说的听明白的,直接粘了
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int maxn=2e5+10;
using namespace std;
int n,ans;
string s[maxn];
bool flag[26],vis[26];
struct lsx
{
int tr[maxn][26],cnt[maxn],n;
lsx():n(0){}
void insert(string s,bool k)
{
int p=0;
if(k)
{
for(int i=0;i<s.size();i++)
{
int t=s[i]-'a';
if(!tr[p][t]) tr[p][t]=++n;
p=tr[p][t];
}
}
else
{
for(int i=s.size()-1;i>=0;i--)
{
int t=s[i]-'a';
if(!tr[p][t]) tr[p][t]=++n,cnt[t]++;
p=tr[p][t];
}
}
}
}t1,t2;
signed main()
{
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
t1.insert(s[i],1);
t2.insert(s[i],0);
flag[s[i][s[i].size()-1]-'a']=1;
if(s[i].size()==1&&!vis[s[i][0]-'a']){ans++,vis[s[i][0]-'a']=1;}
}
// return 0;
for(int i=1;i<=t1.n;i++)
{
for(int j=0;j<=25;j++)
{
if(!t1.tr[i][j])
{
ans+=t2.cnt[j];
// cout<<i<<" "<<j<<endl;
}
else if(flag[j])ans++;
}
}
cout<<ans<<'\n';
return 0;
}
/*
*/