A:
对于
的询问分块,对于
的K,维护序列中
的和,对于
的K,每次询问直接暴力跳
对于
的询问
首先肯定贪心的染颜色数最少的那种颜色,设有
个,将颜色转为标号
~
,若随机值落在
间就是这种颜色,于是一种比较暴力的做法就是直接枚一遍
,计算每个位置贡献的概率带上权累计进答案,这样做是
的
注意到因为
,而且我们选的是最少的那种颜色,所以一定有
因为我们答案只要求4位的精度,当n很大时,其实大概当我们枚举的
的绝对值
时
贡献进答案的概率已经是小数点后好几十位了,他的贡献你计不计算都对答案没有影响
于是我们可以对
做到
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define ld long double
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 210000;
int n,m;
int val[maxn];
ll sum[600][600]; int N;
int T,k,d;
int t[maxn];
int main()
{
freopen("lzz.in","r",stdin);
freopen("lzz.out","w",stdout);
read(n); read(m); N=500;
for(int i=1;i<=n;i++)
{
read(val[i]);
for(int j=1;j<=N;j++) sum[j][i%j]+=val[i];
}
while(m--)
{
int type; read(type);
if(type==1)
{
int x,y; read(x); read(y);
for(int j=1;j<=N;j++) sum[j][x%j]+=y-val[x];
val[x]=y;
}
else
{
read(T); read(k); read(d);
for(int i=1;i<=T;i++) read(t[i]);
if(T==1&&d<=N) { printf("%.4Lf\n",(ld)sum[d][k%d]); continue; }
int mnc=t[1]; for(int i=2;i<=T;i++) mnc=min(mnc,t[i]);
ld ans=val[k];
ld p=1.0;
for(int i=1;i<=200;i++)
{
int x=k+i*d; if(x>n||i>mnc) break;
p=p*((ld)(mnc-i+1)/(n-i));
ans+=p*val[x];
}
p=1.0;
for(int i=1;i<=200;i++)
{
int x=k-i*d; if(x<1||i>mnc) break;
p=p*((ld)(mnc-i+1)/(n-i));
ans+=p*val[x];
}
printf("%.4Lf\n",ans);
}
}
return 0;
}
B:
假设我们不使用跳跃,那么我们从根出发,遍历一遍树再回到根,每条边经过2次,这也是经过次数的上限
我们可以随便画几个跳跃,手玩一下,会发现一次从
到
的跳跃可以使
到
路径上的边都少经过一次
因为要求每条边至少经过一次,所以一条边不能被多个跳跃的链同时覆盖,同时可以通过手玩发现,确定了这些互不相交的跳跃后,一定能构造出一组解使得这些链上的边都少经过一次
转化一下发现就是在这棵树上找不超过
条互不相交的链使他们覆盖的边权和-
链的数量最大
做个DP即可
表示
的子树里有
条链,
向上的父边是否被链占用,最大价值
一个点
合并他的孩子时这个0/1的意义要改一下,改成和孩子连边被占用的边数的奇偶
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 2100;
int n,K,C;
struct edge{int y,c,nex;}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y,const int c){a[++len]=(edge){y,c,fir[x]};fir[x]=len;}
int siz[maxn];
int f[maxn][maxn][2],g[maxn][2];
void dp(int x,int fa)
{
siz[x]=1;
f[x][0][0]=0,f[x][0][1]=0;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa)
{
dp(y,x);
for(int j=0;j<=siz[x]+siz[y]&&j<=K;j++) g[j][0]=g[j][1]=0;
for(int j=0;j<=siz[x];j++) for(int l=0;l<=siz[y]&&j+l<=K;l++)
{
up(g[j+l][0],f[x][j][0]+f[y][l][0]);
up(g[j+l][1],f[x][j][0]+f[y][l][1]+a[k].c);
up(g[j+l][1],f[x][j][1]+f[y][l][0]);
up(g[j+l+1][0],f[x][j][1]+f[y][l][1]+a[k].c-C);
}
siz[x]+=siz[y];
for(int j=0;j<=siz[x]&&j<=K;j++) f[x][j][0]=g[j][0],f[x][j][1]=g[j][1];
}
}
int main()
{
freopen("mzz.in","r",stdin);
freopen("mzz.out","w",stdout);
while(scanf("%d%d%d",&n,&K,&C)!=EOF)
{
memset(fir,0,sizeof fir); len=0;
int sum=0;
for(int i=1;i<n;i++)
{
int x,y,c; scanf("%d%d%d",&x,&y,&c); x++,y++;
ins(x,y,c); ins(y,x,c);
sum+=c<<1;
}
for(int i=1;i<=n;i++) for(int j=0;j<=K;j++) f[i][j][0]=f[i][j][1]=0;
dp(1,0);
int ans=0;
for(int i=0;i<=K;i++) up(ans,f[1][i][0]);
printf("%d\n",sum-ans);
}
return 0;
}
C:
不会做
看不懂题解
弃疗
……