noip模拟7

新的阶乘

考虑从这个式子下手,怎么更优秀的求得答案。

f(x)=x1×(x1)2×(x2)3...2x1×1x=k=0x1(xk)k+1=x!×k=0x2(x1k)k+1=x!×f(x1)=k=1xk!=k=1xkxk+1

那么我们只需要考虑对于区间 [1,n] 内的所有数,一个数的贡献就是质因数的个数 +xk+1

如果从每个数开始进行质因数分解,时间复杂度是 O(nn),不能接受啊。

那么我们可以仿照埃筛的思想,对于每个质数,找到它的所有倍数,对那个数进行贡献,那思路就非常清晰了。

因为会有多个同样质因数的情况,所以需要对枚举的倍数进行拆分。

总时间复杂度约为 O(nlognloglogn)

能过反正。

(据说这题是今年百度之星初赛的题,这么强吗?)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
const int N=1e7+7;
int ans[N];
bitset<N>vis;
void calc()
{
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
for(int j=1;j*i<=n;j++)
{
vis[j*i]=1;
int k=j*i;
while(k%i==0) ans[i]+=(n-(j*i)+1),k/=i;
}
}
}
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
signed main()
{
freopen("factorial.in","r",stdin);
freopen("factorial.out","w",stdout);
scanf("%lld",&n);
calc();
int flag=0;
printf("f(%lld)=",n);
for(int i=1;i<=n;i++)
{
if(ans[i]==0) continue;
if(flag)putchar('*');
if(ans[i]==1) write(i);
else write(i),putchar('^'),write(ans[i]);
flag=1;
}
return 0;
}

博弈树

结论题。

如果在直径中点那么 Bob 获胜,否则 Alice 获胜。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int head[N],ecnt{};
struct EDGE{
int nxt,to;
}e[N<<2];
inline void add(int u,int v)
{
e[++ecnt].nxt=head[u];
head[u]=ecnt;
e[ecnt].to=v;
}
int f[N],d[N];
int maxval{},maxpos;
inline void dfs1(int u,int fa)
{
f[u]=fa,d[u]=d[fa] + 1;
if(d[u]>maxval) maxval=d[u],maxpos=u;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs1(v,u);
}
}
int dfn[N],cnt{};
inline void dfs2(int u,int fa)
{
if(fa==0) maxval=fa;
f[u]=fa,d[u]=d[fa]+1;
dfn[u]=++cnt;
if(d[u]>maxval) maxval=d[u],maxpos=u;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs2(v,u);
}
}
vector<int>zj;
bool fnd=0;
inline void dfs3(int u,int fa)
{
if(u==maxpos)
{
fnd=1;zj.push_back(u);return;
}
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs3(v,u);
if(fnd) {zj.push_back(u);return;}
}
}
signed main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int n,q;cin>>n>>q;
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(1,0);
int rt=maxpos;
dfs2(rt,0),dfs3(rt,0);
int siz=zj.size();
int pos=0;
if(siz%2==1) pos=zj.at(siz>>1);
while(q--)
{
int u;cin>>u;
if(pos==u) puts("Bob");
else puts("Alice");
}
return 0;
}

划分

其实很简单。我们考虑分两种情况讨论。

第一种是题目给的特殊性质,满足 i[1,k],ai=0。这种情况就是前 m 个空,mk,能插最多 k 个板,那么划分成 k 段的方案数就是 (mk1)

但是题目上说可以划分成大于等于 k 段,那总方案数就是 i=k1m(mi)

另一种情况,我们想到之前那个划分线段集合的题。那道题有一个贪心策略就是找 k1 个单个的线段去确保答案最大。而这道题可以沿用这种策略。考虑选取一个长度为 nk+1 的字典序最大的段,因为要保证最大的数的位数最多,这样才能使答案最大。其他 k1 段就是单个的点。

然后,考虑到一个二进制数的最后一位可以更改,那么我们只需要使用哈希去匹配有多少长度为 nk 的子串是和最大答案相匹配的,统计即为答案。

题目里有 hack 数据,你需要找一个较为优秀的模数去双哈希,要不然会有一个点卡住。

考虑有边界情况 n=k,这时候答案是 k=1n[ai=1],方案数为 1

顺便拿了最优解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
const int N=2e6+5;
char c[N];
const int mod=998244353;
int mx=0;
int ppow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=(res*a)%mod;
a=(a*a)%mod,b>>=1;
}return res;
}
int f[N],g[N];
void init()
{
f[0]=g[0]=1;
for(int i=1;i<=n;i++)f[i]=(f[i-1]*i)%mod;
g[n]=ppow(f[n],mod-2);
for(int i=n-1;i>=1;i--)g[i]=(g[i+1]%mod*(i+1)%mod);
}
int getc(int a,int b)
{
return f[a]*g[a-b]%mod*g[b]%mod;
}
#define ull unsigned long long
ull p=13331,p1=1313131;
const ull md=20091119;
ull hs[N],pp[N];
ull hs1[N],pp1[N];
signed main()
{
// freopen("C-ex-2.in","r",stdin);
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>k;
cin>>(c+1);
if(n==k)
{
int ccnt=0;
for(int i=1;i<=n;i++) ccnt+=(c[i]=='1');
return cout<<ccnt<<" 1",0;
}
bool _=1;
for(int i=1;i<=k;i++) _&=(c[i]=='0');
if(_)
{
int ans=0;
for(int i=k+1;i<=n;i++) ans=((ans*2ll)%mod+c[i]-'0')%mod;
init();
int ans2=0,cnt=0;
for(int i=1;i<=n;i++)
{
if(c[i]=='1')break;
++cnt;
}
if(cnt==n)--cnt;
for(int i=k-1;i<=cnt;i++)ans2=(ans2+getc(cnt,i))%mod;
cout<<ans%mod<<" "<<ans2%mod<<"\n";
return 0;
}
int len=n-k+1;
int mxpos=1;
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
int now=mxpos-1;
bool flag=0;
for(int k=i;k<=j;k++)
{
now++;
if(c[k]==c[now])continue;
if(c[k]>c[now]) {flag=1;break;}
else break;
}
if(flag) mxpos=i;
}
// cout<<mxpos;
int ans1=0;
for(int i=mxpos;i<=mxpos+len-1;i++) ans1=(ans1*2)%mod+c[i]-'0';
for(int i=1;i<mxpos;i++) ans1=(ans1+c[i]-'0')%mod;
for(int i=mxpos+len;i<=n;i++) ans1=(ans1+c[i]-'0')%mod;
cout<<ans1<<" ";
ull cmp=0,cmp1=0;pp[0]=1,pp1[0]=1;
for(int i=1;i<=n;i++)
{
hs[i]=hs[i-1]*p+(int)c[i];
pp[i]=pp[i-1]*p;
hs1[i]=hs1[i-1]*p1%md+(int)c[i];
hs1[i]%=md;
pp1[i]=pp1[i-1]*p1%md;
}
int ans2=0;
for(int i=mxpos;i<mxpos+len-1;i++) cmp=cmp*p+(int)c[i];
for(int i=mxpos;i<mxpos+len-1;i++) cmp1=cmp1*p1%md+(int)c[i],cmp1%=md;
cmp1%=md;
for(int i=1;i+len-1<=n;i++)
{
ull now=hs[i+len-2]-hs[i-1]*pp[len-1];
ull now2=((hs1[i+len-2]-hs1[i-1]*pp1[len-1]%md+md)%md+md)%md;
if(now==cmp&&now2==cmp1)++ans2,ans2%=mod;
}
cout<<ans2;
return 0;
}
/*
21 3
10010101010101110011111
10 6
0000000000
*/

灯笼

你会吗?我不会。

posted @   ccjjxx  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示