前言:从未绝望的一天
JZOJ 3388 绿豆蛙的归宿
题目
给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出发能够到达所有的点,所有的点也都能够到达终点。从起点走向终点,到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。求从起点走到终点的所经过的路径总长度期望。
分析
设 表示从节点 走到终点所经过的路径的期望长度,那么根据数学期望的定义和性质,得 ,两种方法,一种正向深搜,还有反向广搜,各有优缺,then
代码
#include <cstdio>
#include <cctype>
using namespace std;
struct node{int y,w,next;}e[200001];
int ls[100001],deg[100001],n,m;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
double dfs(int x){
double ans=0; if (!ls[x]) return 0;
for (int i=ls[x];i;i=e[i].next) ans+=(dfs(e[i].y)+e[i].w)*1.0/deg[x];
return ans;
}
int main(){
n=in(); m=in(); int x;
for (int i=1;i<=m;i++){
x=in(); e[i].y=in(); e[i].w=in();
deg[x]++; e[i].next=ls[x]; ls[x]=i;
}
return !printf("%.2lf",dfs(1));
}
JZOJ 3467 最长上升子序列
题目:可持久化LIS
分析:离线处理,用O(nlogn)的时间求LIS
代码
#include <cstdio>
#include <cctype>
#include <stack>
#define N 500001
using namespace std;
int a[N],pnt[N],ans[N],ls[N],nxt[N]; bool flag[N];
int len,n,l,rem[N],p[N],id[N],b[N],c[N]; stack<int>st;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void add(int x,int y){nxt[++l]=ls[x]; ls[x]=l; rem[l]=y;}
void dfs(){
p[0]=-1; int length=0;
id[0]=ls[0]; st.push(0);
while (st.size()){
if (!id[st.top()]){//没有出现
int t=st.top(); st.pop();
if (!flag[t]) length--;//不是答案
else p[b[t]]=c[t];//记录
}
else{
int t=rem[id[st.top()]];
id[st.top()]=nxt[id[st.top()]];
st.push(t); id[t]=ls[t];
if (a[t]>p[length]) flag[t]=0,p[++length]=a[t];//超过了长度
else{
flag[t]=1;//需要找答案
int l=0,r=length+1;
while (l<r){//二分查找
int mid=(l+r)>>1;
if (a[t]>p[mid]) l=mid+1;
else r=mid;
}
b[t]=l; c[t]=p[l]; p[l]=a[t];
}
ans[t]=length;
}
}
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int main(){
freopen("lis.in","r",stdin);
freopen("lis.out","w",stdout);
bool x; int y,now=0; n=in();
for (int i=1;i<=n;i++){
x=in(); y=in();
if (!x) add(now,++len),a[(now=len)]=y; //全新版本
else now=pnt[y]; pnt[i]=now;//当前版本
}
dfs();
for (int i=1;i<=n;i++,putchar('\n'))
if (ans[pnt[i]]) print(ans[pnt[i]]); else putchar('0');
return 0;
}
JZOJ 3468 osu!
题目
在长度为 的01串中,若连续的 个1可得到 的分数,每个位置选择1都有概率,问期望得到的分数。
分析
动态规划, 表示前 位且第 位为1的期望得到的分数,根据完全立方公式 ,可以在每一位处理当前的答案。
代码
#include <cstdio>
using namespace std;
int n; double d,f,g,h;
int main(){
freopen("osu.in","r",stdin);
freopen("osu.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%lf",&d);
f+=d*(3*(h+g)+1);//乘概率
h=d*(h+2*g+1);
g=d*(g+1);
}
return !printf("%.1lf",f);
}
JZOJ 3389 Heaven Cow与God Bull
题目:求 ,使 最大。
分析:
所以
也就是
需要最小,说明质数的个数要尽量多,所以就是最小值最大(最大是因为质数个数多说明要大),所以离线+二分,具体如何优化?
由于比较懒,所以eratosthenes筛法,我的优化是质数2时提前处理(特判n是1)然后偶数就可以不理它了,所以大概就是
问题是还要高精度乘单精度,所以压16位(不想再压了,不然炸了就不好了),共
也很大了,突然发现在线查询超时是必然的,之后离线完二分查找,大概就是
,最后总计
,end
代码
#include <cstdio>
#define mod 10000000000000000
typedef long long ll; typedef unsigned short ust; char n[25001];
ll ans[5853][1563],a[1563]; ust tot=0,len[5853]; bool v[28891]; int len2;
bool check(int x){
if (len[x]!=(len2+1)) return len[x]<(len2+1);
for (ust i=len2;i;i--)
if (ans[x][i]!=a[i]) return ans[x][i]<a[i];
return ans[x][0]<=a[0];
}
void out(ll ans){if (ans>9) out(ans/10); putchar(ans%10+48);}
void print(ust x){
for (int i=len[x]-1;i>=0;i--){
ll k=mod/10;
if (i!=len[x]-1)
while (ans[x][i]<k&&k>1) putchar('0'),k/=10;
if (ans[x][i]) out(ans[x][i]);
}
putchar('\n');
}
int main(){
ans[0][len[0]++]=2ll;
for (ust i=1;i<=28890;i++)//eratosthenes筛法
if (!v[i]){
ust k=i<<1|1; len[++tot]=len[tot-1]; ll s,g=0,h;
for (ust j=0;j<len[tot];j++){//压16位高精度
h=((long double)ans[tot-1][j]*k+g)/mod;//求商
s=ans[tot-1][j]*k+g-h*mod;
if (s<0) s+=mod; else if (s>=mod) s-=mod;
ans[tot][j]=s; g=h;
}
while (g) ans[tot][len[tot]++]=g%mod,g/=mod;
for (ust j=i;j<=28890/k;j++) v[k*(j<<1|1)>>1]=1;//诡异的筛法
}
char c=getchar(); ust t=0,len1; ll k;
while (c<48||c>57) c=getchar();
while (c>=48&&c<=57) t=t*10+c-48,c=getchar();
while (t--){
c=getchar(); len1=len2=0; k=1; ust j=0; a[0]=0;
while (c<48||c>57) c=getchar();
while (c>=48&&c<=57) n[++len1]=c,c=getchar();
for (ust i=len1;i>=1;i--){//压16位存储
j++; a[len2]+=(n[i]-48)*k;
k=(k<<1)+(k<<3); if (j==16) j=0,k=1,a[++len2]=0;
}
if (!j) len2--; if (!len2&&a[len2]==1) {putchar('1'); continue;}
ust l=0,r=tot;
while (l<r){//二分
ust mid=(l+r+1)>>1;
if (check(mid)) l=mid; else r=mid-1;
}
print(l);
}
return 0;
}
后续
洛谷 4316 codevs 2488 绿豆蛙的归宿 洛谷 1654 osu!