F:node
/* 根据上面的推导就变成了最后一个式子 暴力能过(加一些乱七八糟的东西) 由于n/i的结果是 相似 n n-1 n-1 n-2 n-2 n-2 n-3 n-3 n-3.... 的东西(好像是有logn种),因此稍微存一下已经处理过得答案 而后在根据1e7以内莫比乌斯函数不为零的 只有3e6个大约 1300ms */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 10000010 #define ll long long #define mod 998244353 using namespace std; int n,mu[maxn],f[maxn],prime[maxn/10],num; int k[maxn],m; ll ans,vis[maxn]; void Mbs(){ mu[1]=1; for(int i=2;i<=10000000;i++){ if(f[i]==0){ prime[++num]=i;mu[i]=-1; } for(int j=1;j<=num;j++){ if(prime[j]*i>10000000)break; f[prime[j]*i]=1; if(i%prime[j]==0){ mu[prime[j]*i]=0;break; } mu[prime[j]*i]=-mu[i]; } } for(int i=1;i<=10000000;i++) if(mu[i]!=0)k[++m]=i; } ll Cal(int x){ if(vis[x])return vis[x]; ll res=0,d; for(int i=1;i<=m;i++){ if(k[i]>x)break; d=k[i];if(x/d==0)break; res=((res+mu[d]*(x/d)*(x/d)%mod)%mod+mod)%mod; } vis[x]=res; return res; } int main(){ scanf("%lld",&n);Mbs(); for(int i=1;i<=m;i++){ if(k[i]>n)break; int x=k[i]; ans=((ans+mu[x]*Cal(n/x)%mod)%mod+mod)%mod; } printf("%lld\n",ans); return 0; } /* 太慢了 上面的结论,其实不用存下来 咱们想要的是对于ij n/i==n/j 能不能只算一次 能够的 观察最后的式子 发现Cal返回的值是同样的,只有mu不同 那就维护mu的前缀和 一段一段的求 就快起来了 300+ms */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 10000010 #define ll long long #define mod 998244353 using namespace std; ll n,mu[maxn],f[maxn],prime[maxn/10],num,ans; void Mbs(){ mu[1]=1; for(ll i=2;i<=10000000;i++){ if(f[i]==0){ prime[++num]=i;mu[i]=-1; } for(ll j=1;j<=num;j++){ if(prime[j]*i>10000000)break; f[prime[j]*i]=1; if(i%prime[j]==0){ mu[prime[j]*i]=0;break; } mu[prime[j]*i]=-mu[i]; } } for(ll i=1;i<=10000000;i++) mu[i]+=mu[i-1]; } ll Cal(ll x){ ll res=0; for(ll i=1,j;i<=x;i=j+1){ j=x/(x/i); res=((res+(mu[j]-mu[i-1])*(x/i)*(x/i)%mod)%mod+mod)%mod; } return res; } int main(){ scanf("%lld",&n);Mbs(); for(ll i=1,j;i<=n;i=j+1){ j=n/(n/i); ans=((ans+(mu[j]-mu[i-1])*Cal(n/i)%mod)%mod+mod)%mod; } printf("%lld\n",ans); return 0; }
H:ios
/* 介于每一个点之间没有影响 咱们能够求出每一个点是黑的指望 而后还差q步的涂白 用二维bit搞搞就行了 */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 1010 #define ll long long #define mod 998244353 using namespace std; ll n,m,q,g[maxn][maxn],a[maxn][maxn],ans; ll qc(ll a,ll b){ ll res=1;while(b){ if(b&1)res=res*a%mod; a=a*a%mod;b>>=1; } return res; } void Insert(ll x,ll y,ll z){ for(ll i=x;i<=n;i+=i&(-i)) for(ll j=y;j<=m;j+=j&(-j)) a[i][j]+=z; } ll Query(ll x,ll y){ ll res=0; for(ll i=x;i>0;i-=i&(-i)) for(ll j=y;j>0;j-=j&(-j)) res+=a[i][j]; return res; } int main(){ scanf("%lld%lld%lld",&n,&m,&q); ll l,r,sum; for(ll i=1;i<=n;i++){ scanf("%lld%lld",&l,&r); sum=(r-l+1)*(r-l+2)/2; for(ll j=l;j<=r;j++) g[i][j]=(j-l+1)*(r-j+1)%mod*qc(sum,mod-2)%mod; } ll x1,x2,y1,y2; while(q--){ scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2); Insert(x2+1,y2+1,-1);Insert(x1,y1,-1); Insert(x2+1,y1,1);Insert(x1,y2+1,1); } for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) if(Query(i,j)>=0)ans=(ans+g[i][j])%mod; printf("%lld\n",ans); return 0; }
I:函数
/* 带权并茶几 假设咱们有了每一个人当前和A我的打过架 其中a次作主场,b次作客场 那么方案数为3^(n-A)*2^a 下面考虑处理出A a b y去打x这件事,x主场,y客场, 原来全部可能在y座位上的人,要想赢,则b++ 原来全部可能在x座位上的人,想要赢,则a++ 大致上就是一个裸地带权并茶几,每次find的时候拿起路上的ab值 可是有个问题就是 y连到了x上,那么y的孩子们find的时候会把x的 ab值加上 显然不对 每次合并,虚拟出来一个点,xy都连向它,它的ab值为零 而后就行了 */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 800010 #define ll long long #define mod 998244353 using namespace std; ll n,m,fa[maxn],a[maxn],b[maxn]; struct node{ ll a,b,fa; }; ll find(ll x){ if(x==fa[x])return x; ll fat=fa[x]; fa[x]=find(fa[x]); a[x]+=a[fat]; b[x]+=b[fat]; return fa[x]; } ll Qc(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%mod; b>>=1;a=a*a%mod; } return res; } ll Cal(ll x){ find(x);ll A=a[x]+b[x]; ll ans=Qc(3,n-A); ans=ans*Qc(2,a[x])%mod; return ans; } int main(){ scanf("%lld%lld",&n,&m); for(ll i=1;i<=n*4;i++)fa[i]=i; ll c,x,y,now=n; for(ll i=1;i<=m;i++){ scanf("%lld",&c); if(c==1){ scanf("%lld%lld",&x,&y); ll fx=find(x);ll fy=find(y); a[fx]++;b[fy]++;fa[fx]=++now;fa[fy]=now; } else { scanf("%lld",&x);printf("%lld\n",Cal(x)); } } }