题解 P6860 【象棋与马】
出题人先来报个到,比赛的时候发现许多选手的做法都和我的不一样/kk。也有莫比乌斯反演过了的神仙。也十分感谢本题的验题人 beginend 和 my_dog。
T4 象棋与马
这个马能走到全图的充要条件显然是它能走到
算法1:
暴力 bfs 看是否能到达
期望得分
算法2:
请注意下文中
考虑从数论角度考虑本题。
首先如果当
因为走的顺序时无所谓的,所以可以将走的路程分成两段,一段只有是
显然对于第一段能走到的点可以表示为
设
解第一个方程组得到
同理第二个方程组可以推出
第三个方程组推出
第四个方程组推出
所以
然后暴力求出所有的
算法3:
如果
定义
显然如果
如果
那么显然线性求
算法4:
显然答案就是奇数的
若
然后用杜教筛求出
期望得分
算法5:
其实最终式子可以优化为递推式
看到最终许多通过的选手都是写成这种形式的
others
对于
然后还有人写到
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll unsigned long long
using namespace std;
const ll N=1e7+1;
ll T,n,cnt,mu[N],phi[N],pri[N];
ll sp1[N],sp2[N],p1[1100],p2[1100];
bool vis[N];
map<ll,ll> sp,sm;
void prime(){
phi[1]=1;
for(ll i=2;i<N;i++){
if(!vis[i])pri[++cnt]=i,phi[i]=i-1;
for(ll j=1;j<=cnt&&pri[j]*i<N;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[pri[j]]*phi[i];
}
}
for(ll i=1;i<N;i++){
sp1[i]=sp1[i-1]+phi[i]*(i&1);
sp2[i]=sp2[i-1]+phi[i]*(!(i&1));
}
return;
}
ll GetSphi(ll n){
if(n<N)return sp1[n]+sp2[n];
if(sp[n])return sp[n];
ll rest=(n%2ull==0ull)?((ll)n/2ull*(n+1ull)):((ll)(n+1ull)/2ull*n);
for(ll l=2ull,r;l<=n;l=r+1ull)
r=n/(n/l),rest-=(r-l+1ull)*GetSphi(n/l);
return (sp[n]=rest);
}
void dfs(ll x,ll n){
p1[x]=p2[x]=0;
if(n<N){
p1[x]=sp1[n];
p2[x]=sp2[n];
return;
}
dfs(x+1,n/2);
p2[x]+=p1[x+1]+p2[x+1]*2ull;
p1[x]+=GetSphi(n)-p2[x];
return;
}
int main()
{
prime();
scanf("%llu",&T);
while(T--){
scanf("%llu",&n);dfs(0,n);
printf("%llu\n",p1[0]+p2[0]*2ull-1ull);
}
}