noip模拟33
A.Hunter
看到数据范围,想到要么\(O(n)\),要么\(O(nlogn)\)..
想着搞一搞数据结构,却丝毫没有考虑到期望的线性性质..
考虑每个猎人对第一个猎人的贡献,发现两者之间的死亡顺序的期望可以轻松求出。于是将期望累加得到答案..
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigend ll
#define re register ll
#define lf double
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memset(x,y,sizeof x)
inline ll read() {
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1e6+55;
const ll mod=998244353;
ll n,m,sum;
ll w[N];
inline ll ksm(ll a,ll b,ll c){
a%=c; ll temp=1;
while(b){
if(b&1) temp=(temp*a)%c;
a=(a*a)%c; b>>=1;
}
return temp%c;
}
signed main(){
n=read(); ll temp;
for(re i=1;i<=n;i++) w[i]=read();
for(re i=2;i<=n;i++){
temp=w[i]*ksm(w[1]+w[i],mod-2,mod)%mod;
sum=(sum+temp)%mod;
}
++sum;
printf("%lld",sum%mod);
return 0;
}
B.Defence
裸的线段树合并,认真审题即可..
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigend ll
#define re register ll
#define lf double
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memset(x,y,sizeof x)
inline ll read() {
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1e5+50;
ll m,n,q,ts,tot,flag;
ll head[N],rt[N*64],ls[N*64],rs[N*64],sum[N*64],lc[N*64],rc[N*64],len[N*64],ans[N];
struct I { ll u,v,nxt; } e[N<<1];
inline void add(ll u,ll v){
e[++ts].u=u;
e[ts].v=v;
e[ts].nxt=head[u];
head[u]=ts;
}
inline void pushup(ll x,ll l,ll r){
sum[x]=sum[ls[x]]+sum[rs[x]];
ll mid=(l+r)>>1,llen=mid-l+1,rlen=r-mid;
/* if(x==rt[3]) {cout<<"Three\n";
cout<<"sum:"<<sum[ls[x]]<<" "<<sum[rs[x]]<<'\n';
cout<<l<<" "<<r<<" "<<lc[ls[x]]<<" "<<rc[ls[x]]<<" "<<lc[rs[x]]<<" "<<rc[rs[x]]<<endl;
cout<<"L R:"<<llen<<" "<<rlen<<'\n';}
*/ if((!sum[ls[x]]) and (!sum[rs[x]])){
len[x]=r-l+1;
lc[x]=0; rc[x]=0;
} else
if(!sum[ls[x]]){
len[x]=max(lc[rs[x]]-mid-1+llen,len[rs[x]]);
lc[x]=lc[rs[x]]; rc[x]=rc[rs[x]];
} else
if(!sum[rs[x]]){
len[x]=max(mid-rc[ls[x]]+rlen,len[ls[x]]);
lc[x]=lc[ls[x]]; rc[x]=rc[ls[x]];
} else
if(sum[ls[x]] and sum[rs[x]]){
len[x]=max(len[ls[x]],len[rs[x]]);
len[x]=max(len[x],lc[rs[x]]-rc[ls[x]]-1);
lc[x]=lc[ls[x]]; rc[x]=rc[rs[x]];
}
// if(rt[3]==x) cout<<"len:"<<len[x]<<endl<<endl;
return ;
}
void merge(ll &x,ll y,ll l,ll r){
if(!x) { x=y; return ; }
if(!y) return ;
if(l==r){
sum[x]=sum[x]|sum[y];
if(sum[x]){
lc[x]=l;
rc[x]=l;
len[x]=0;
}
else{
lc[x]=0;
rc[x]=0;
len[x]=1;
}
return ;
}
ll mid=(l+r)>>1;
merge(ls[x],ls[y],l,mid);
merge(rs[x],rs[y],mid+1,r);
pushup(x,l,r);
return ;
}
void update(ll &x,ll l,ll r,ll pos){
if(!x) x=++tot;
if(l==r){
sum[x]=1; len[x]=0;
lc[x]=l,rc[x]=l;
return ;
}
ll mid=(l+r)>>1;
if(pos<=mid) update(ls[x],l,mid,pos);
else update(rs[x],mid+1,r,pos);
pushup(x,l,r);
return ;
}
void dfs(ll now,ll dad){
if(flag) return ;
for(re i=head[now];i;i=e[i].nxt){
if(e[i].v==dad) continue;
dfs(e[i].v,now);
if(flag) return ;
merge(rt[now],rt[e[i].v],1,m);
}
// if(now==3) cout<<lc[rt[now]]<<" skr "<<rc[rt[now]]<<" "<<len[rt[now]]<<endl;
ll temp=lc[rt[now]]-1+m-rc[rt[now]];
ans[now]=max(0*1ll,len[rt[now]]-temp)+temp;
return ;
}
signed main(){
n=read(); m=read(); q=read();
ll u,v,w;
for(re i=2;i<=n;i++){
u=read(); v=read();
add(u,v); add(v,u);
}
for(re i=1;i<=q;i++){
u=read();
update(rt[u],1,m,read());
}
dfs(1,0);
for(re i=1;i<=n;i++){
if(!rt[i]) puts("-1");
else printf("%lld\n",ans[i]);
}
return 0;
}
C.Connect
直接想到了最大生成树,设\(path(1,n)\)为主路径,那么在最大生成树的基础上,在非主路径上各种连边即可..
但是这个东西应该是可以被轻松\(Hack\)的,这类题应该多去画图,自己多去手模几组样例,并及时进行对拍..
正解是在链的基础上进行两种操作:
<1> 将链的长度增加\(1\);
<2> 在链的某个节点\(x\)上连一坨点..且保证这些点只和\(x\)联通..
然后状压转移即可.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigend ll
#define re register ll
#define lf double
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memset(x,y,sizeof x)
inline ll read() {
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=19;
ll n,m,sum,U;
ll d[N][N],f[1<<N][N];
ll dp[1<<N][N];
signed main(){
n=read(); m=read();
ll u,v,temp=0; U=(1<<n)-1;
for(re i=1;i<=m;i++){
u=read(); v=read();
d[u][v]=d[v][u]=read();
sum+=d[u][v];
}
for(re i=1;i<=U;i++){
temp=0;
for(re j=1;j<=n;j++){
if((i>>(j-1))&1)
for(re k=j+1;k<=n;k++)
if((i>>(k-1))&1) temp+=d[j][k];
}
for(re j=1;j<=n;j++){
f[i][j]=temp;
if(!((i>>(j-1))&1)){
for(re k=1;k<=n;k++)
if((i>>(k-1))&1) f[i][j]+=d[k][j];
}
}
}
ll S,res=0;
for(re i=1;i<=U;i++){
if(!(i&1)) continue;
for(re j=1;j<=n;j++){
if((i>>(j-1))&1){
for(re k=1;k<=n;k++){
if((i>>(k-1))&1) continue;
dp[i|(1<<(k-1))][k]=max(dp[i|(1<<(k-1))][k],dp[i][j]+d[j][k]);
}
S=U xor i;
for(re T=S;T;T=(T-1)&S){
for(re k=1;k<=n;k++){
if((i>>(k-1))&1){
dp[i|T][j]=max(dp[i|T][j],dp[i][j]+f[T][k]);
}
}
}
}
}
}
printf("%lld",sum-dp[U][n]);
return 0;
}