题解 P5589 【小猪佩奇玩游戏】
放一篇不太一样的题解(大雾
首先考虑将题目转化成图论模型,让
然后会发现这些图都长一个样
不妨设当前被考虑到的点为
然后会发现这些图对于答案的贡献之和此图的大小有关,而图的大小又是
于是问题转化为给定一个大小为
就会想到写个状压去算某一张图的贡献...
当然状压的确是可以将答案算出来的,但是复杂度是
于是就会想到真的需要的
然而这些状态实际上依赖的状态存在大量相同而且真正有效的
但是这样还是很慢
所以就会想到要打表
提前用
但是实际上对于某一个
于是真正要计算的点就只有
复杂度大约是
然后要特判
#include<bits/stdc++.h>
using namespace std ;
#define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int N = 35000 ;
const int M = 35 ;
double Ans[M] = { 0, 1.0, 1.5, 2.0, 2.33333333333333, 2.83333333333333, 3.08333333333333,
3.5833333333333, 3.8333333333333, 4.16666666666667, 4.4166666666667, 4.91666666666667, 5.08333333333333, 5.58333333333333,
5.8333333333333, 6.0833333333333, 6.28333333333333, 6.7833333333333, 6.95, 7.45, 7.61666666667,
7.8666666666667, 8.11666666666667, 8.6166666666667, 8.741666666667, 9.075, 9.325, 9.575, 9.741666666667,
10.2416666666667, 10.3666666666667 };
int n, vis[N], rU ;
signed main()
{
int T = gi() ;
while( T-- ) {
n = gi() ; int cnt = sqrt(n), k = 0, j ;
if( cnt * cnt <= n ) ++ cnt ;
double ans = 1 ; rU = n - cnt ;
memset( vis, 0, sizeof(vis) ) ;
rep( i, 2, cnt ) {
if( vis[i] ) continue ;
for( j = i, k = 0; j <= n; j *= i, ++ k ) {
if( j > cnt ) -- rU ;
else vis[j] = 1 ;
} ans += Ans[k] ;
}
if( cnt <= n ) printf("%.8lf\n", ans + rU ) ;
else printf("%.8lf\n", ans ) ;
}
return 0 ;
}
打表程序:
#include<bits/stdc++.h>
using namespace std ;
#define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
#define re register
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int M = 35 ;
double Ans[M] ;
int m ;
int get( int x ) {
int ans = 0 ;
while( x ) ans += ( x & 1 ), x >>= 1 ;
return ans ;
}
map<int, double> dp ;
double Dp( int i ) {
if( dp[i] || i == 0 ) return dp[i] ;
int len = get(i) ;
for( re int j = 1; j <= m; ++ j ) {
if( ( 1 << ( j - 1 ) ) & i ) {
int rk = 0 ;
for( re int k = j; k <= m; k += j ) {
if( ( 1 << ( k - 1 ) ) & i ) rk |= ( 1 << ( k - 1 ) ) ;
}
dp[i] = ( dp[i] + ( 1.0 / len ) * ( 1.0 + Dp(i ^ rk) ) ) ;
}
}
}
signed main()
{
m = 30 ; int maxn = ( 1 << m ) - 1, rnt = 1 ;
printf("%d\n", m ) ;
for( re int rnt = 1; rnt <= m; ++ rnt ) {
printf("%d %.8lf\n", rnt, Dp( ( 1 << rnt ) - 1 ) ) ;
}
return 0 ;
}