。。。被05卡了全场
06
保存前缀和的模m值,对于每一个值找它第一次出现的地方即可。
const int N = 1e5 + 5;
int n , m , a[N];
int s[N] , p[N];
int main()
{
int i , j;
while (~scanf("%d%d",&n,&m))
{
for (i = 1 ; i <= n ; ++ i)
scanf("%d",&a[i]) , s[i] = (s[i - 1] + a[i] + 20000 * m) , s[i] %= m;
int ans = 0;
memset(p , -1 , sizeof(p));
p[0] = 0;
for (i = 1 ; i <= n ; ++ i)
{
if (!~p[s[i]])
p[s[i]] = i;
else ans = max(ans , i - p[s[i]]);
}
cout << ans << endl;
}
return 0;
}
07
每一位是独立的,就可以分别进行一个DP,找出每一位是1的概率再累加。
const int N = 205;
int a[N] , n , ca;
char o[N][2];
double f[20][N][2] , p[N];
int main()
{
int i , j , k;
while (~scanf("%d",&n))
{
printf("Case %d:\n" , ++ ca);
for (i = 0 ; i <= n ; ++ i)
scanf("%d",&a[i]);
for (i = 1 ; i <= n ; ++ i)
scanf("%s", o[i]);
for (i = 1 ; i <= n ; ++ i){
scanf("%lf", &p[i]);
p[i] = 1. - p[i];
}
memset(f , 0 , sizeof(f));
for (i = 0 ; i < 20 ; ++ i)
if (a[0] & (1 << i))
f[i][0][1] = 1;
else f[i][0][0] = 1;
double ans = 0;
for (i = 19 ; i >= 0 ; -- i)
{
for (j = 1 ; j <= n ; ++ j)
{
if (o[j][0] == '&')
{
if (a[j] & (1 << i))
f[i][j][0] = f[i][j - 1][0] * (1.0 - p[j]) + f[i][j - 1][0] * p[j],
f[i][j][1] = f[i][j - 1][1] * (1.0 - p[j]) + f[i][j - 1][1] * p[j];
else
f[i][j][0] = f[i][j - 1][0] * (1.0 - p[j]) + (f[i][j - 1][0] + f[i][j - 1][1]) * p[j],
f[i][j][1] = f[i][j - 1][1] * (1.0 - p[j]);
}
if (o[j][0] == '|')
{
if (a[j] & (1 << i))
f[i][j][1] = f[i][j - 1][1] * (1.0 - p[j]) + (f[i][j - 1][0] + f[i][j - 1][1]) * p[j],
f[i][j][0] = f[i][j - 1][0] * (1.0 - p[j]);
else
f[i][j][0] = f[i][j - 1][0] * (1.0 - p[j]) + f[i][j - 1][0] * p[j],
f[i][j][1] = f[i][j - 1][1] * (1.0 - p[j]) + f[i][j - 1][1] * p[j];
}
if (o[j][0] == '^')
{
if (a[j] & (1 << i))
f[i][j][1] = f[i][j - 1][1] * (1.0 - p[j]) + f[i][j - 1][0] * p[j],
f[i][j][0] = f[i][j - 1][0] * (1.0 - p[j]) + f[i][j - 1][1] * p[j];
else
f[i][j][0] = f[i][j - 1][0] ,
f[i][j][1] = f[i][j - 1][1] ;
}
// printf("0:%lf 1:%lf\n" , f[i][j][0] , f[i][j][1]);
}
// printf("%lf\n" , f[i][n][1]);
ans *= 2.0 , ans += f[i][n][1];
}
printf("%.6lf\n" , ans + 1e-9);
}
return 0;
}
这个平均值只有两种可能,一个是不走圈,就是一条密度最小的路径。一个是把一个圈走无穷次,就是这个圈的密度。
所以只需用floyd求得包含某点的最小密度圈以及两天之间的最小密度路径,就可以得到答案了。
using namespace std;
typedef long long LL;
#define N 105
#define M 200005
int n , m , g[N][N] , f[N][N][N];
double h[N] , w[N][N];
bool p[N][N];
void work()
{
int i , j , k , l , x , y , z;
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
g[i][j] = f[1][i][j] = 1 << 29 , w[i][j] = 1e30 , p[i][j] = 0;
for (i = 1 ; i <= n ; ++ i) h[i] = 1e30;
while (m --)
{
scanf("%d%d%d",&x,&y,&z);
g[x][y] = f[1][x][y] = z;
p[x][y] = 1;
}
for (k = 1 ; k <= n ; ++ k)
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
p[i][j] |= (p[i][k] && p[k][j]);
for (k = 2 ; k <= n ; ++ k)
{
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
{
f[k][i][j] = 1 << 29;
for (l = 1 ; l <= n ; ++ l)
f[k][i][j] = min(f[k][i][j] , f[k - 1][i][l] + g[l][j]);
}
/* for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
printf("%d%c" , f[k][i][j] , " \n"[j == n]);
*/
}
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
if (f[j][i][i] < 1 << 28)
h[i] = min(h[i] , 1.0 * f[j][i][i] / j);
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j) if (p[i][j])
w[i][j] = min(h[i] , h[j]);
for (k = 1 ; k <= n ; ++ k)
for (i = 1 ; i <= n ; ++ i) if (p[i][k])
for (j = 1 ; j <= n ; ++ j) if (p[k][j])
w[i][j] = min(w[i][j] , h[k]);
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
for (k = 1 ; k <= n ; ++ k)
if (f[k][i][j] < 1 << 28)
w[i][j] = min(w[i][j] , 1. * f[k][i][j] / k);
for (i = 1 ; i <= n ; ++ i)
for (j = 1 ; j <= n ; ++ j)
{
if (w[i][j] == 1e30)
printf("NO");
else printf("%.3lf" , w[i][j]);
if (j == n) puts(""); else printf(" ");
}
}
int main()
{
freopen("~input.txt","r",stdin);
freopen("~output.txt","w",stdout);
while (~scanf("%d%d",&n,&m))
//int _; scanf("%d\n" , &_) ; while (_ --)
work();
return 0;
}