BZOJ3207+2802+2318+1933+1934題解 12.11



http://www.lydsy.com/JudgeOnline/problem.php?id=2802

考慮第i個時刻,如果可以賣就賣,賣不出去的話我們有兩種選擇

1、前面賣的某一天不賣,這一次賣

2、這一次不賣


於是我們可以用一個堆來維護一下前面已經賣了的值,當前與堆中最大值比較即可

#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <cstdlib> 
#include <cstring> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <queue>
#define ll long long 
#define For(i,j,k) for(int i=j;i<=k;i++) 
#define Dow(i,j,k) for(int i=j;i>=k;i--) 
using namespace std; 
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f = -1; ch = getchar(); } 
    while(ch>='0'&&ch<='9') { x = x * 10+ch-48; ch = getchar(); } 
    return x * f; 
}
struct node{ll v;int num;node(ll _v,int _n){v=_v;num=_n;}};
bool operator  < (node x,node y)
{
    return x.v<y.v;
}
priority_queue<node> q;
ll a[300001],b[300001],rest,ans,n;
int rec[300001];
int main()
{
    n=read();
    For(i,1,n)  a[i]=read();
    For(i,1,n)  b[i]=read();
    ll rest=0;
    For(i,1,n)
    {
        rest+=a[i];
        if(rest>=b[i])
        {
            rest-=b[i];
            ans++;
            q.push(node(b[i],ans));
            rec[ans]=i;
        }
        else
        {
            if(q.empty())   continue;
            node tmp=q.top();
            if(tmp.v>b[i])   q.pop(),q.push(node(b[i],tmp.num)),rest+=tmp.v-b[i],rec[tmp.num]=i; 
        }
    }
    sort(rec+1,rec+ans+1);
    printf("%lld\n",ans);
    For(i,1,ans)    printf("%d ",rec[i]);
}

http://www.lydsy.com/JudgeOnline/problem.php?id=2318

博弈論日常懵比

一般這種題都是倒推,定義f[i]表示剩餘i個棋子時的先手勝率,g[i]表示剩餘i個棋子時的後手勝率

顯然f[0]=0;g[0]=1;

然後我們考慮f[i]的來源(即轉移)

g[i-1]和g[i]

f[i]=g[i-1]*p+(1-p)*g[i]

同理

g[i]=f[i-1]*q+(1-q)*f[i]

將g[i]的帶入f[i]的方程中

得到

f[i]=g[i-1]*p+(1-p)*(f[i-1]*q+(1-q)*f[i])

化簡得到 f[i]=(p*g[i-1]+(1-p)*q*f[i-1])/(p+q-p*q);

同理得到g[i]

然後考慮到n很大而該遞推式是一個恆係數遞推式,所以我們可以、、卡卡精度

n=min(n,1000)

因爲後面的影響很小

然後就可以做了

#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <cstdlib> 
#include <cstring> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <queue>
#define ll long long 
#define For(i,j,k) for(int i=j;i<=k;i++) 
#define Dow(i,j,k) for(int i=j;i>=k;i--) 
using namespace std; 
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f = -1; ch = getchar(); } 
    while(ch>='0'&&ch<='9') { x = x * 10+ch-48; ch = getchar(); } 
    return x * f; 
}
int T,n;
double p,q,f[2001],g[2001];
int main()
{
    T=read();
    For(ii,1,T)
    {
        n=read();n=min(n,1000);
        scanf("%lf%lf",&p,&q);
        f[0]=0;g[0]=1;
        For(i,1,n)
        {
            if(f[i-1]>g[i-1])    p=1-p,q=1-q;
            f[i]=(p*g[i-1]+(1-p)*q*f[i-1])/(p+q-p*q);
            g[i]=(q*f[i-1]+(1-q)*p*g[i-1])/(p+q-p*q);
            if(f[i-1]>g[i-1])    p=1-p,q=1-q;
        }
        printf("%.6lf\n",f[n]);
    }
}

http://www.lydsy.com/JudgeOnline/problem.php?id=1933

定義dp[i][j][k]表示前i本書中,第二行厚度=j,第三行厚度=k時,最小的h和

然後把i滾存滾掉就好了

#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <cstdlib> 
#include <cstring> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <queue>
#define ll long long 
#define For(i,j,k) for(int i=j;i<=k;i++) 
#define Dow(i,j,k) for(int i=k;i>=j;i--) 
using namespace std; 
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f = -1; ch = getchar(); } 
    while(ch>='0'&&ch<='9') { x = x * 10+ch-48; ch = getchar(); } 
    return x * f; 
}
int dp[2][2201][2201],n;
struct node{int h,v;}   a[301];
inline bool cmp(node x,node y){return x.h>y.h;}
int sum[3001];
inline void upd(int &x,int y){x=x>y?y:x;}
int main()
{
    n=read();
    For(i,1,n)  a[i].h=read(),a[i].v=read();    
    sort(a+1,a+n+1,cmp);
    For(i,1,n)  sum[i]=sum[i-1]+a[i].v;
 
    //dp[i][j][k] 前i本書,第二個書櫃厚j,第三個書櫃厚y,最小高度和 
    int now=1;
    For(i,0,sum[n]) For(j,0,sum[n]) dp[now][i][j]=1e9;  
    dp[now][0][0]=0;
    For(i,1,n)
    {       
        For(ii,0,sum[i])    For(jj,0,sum[i]-ii) dp[now^1][ii][jj]=1e9;  
        For(j,0,sum[i-1])
            For(k,0,sum[i-1]-j)
            {
                upd(dp[now^1][j+a[i].v][k],dp[now][j][k]+(j==0)*a[i].h);
                upd(dp[now^1][j][k+a[i].v],dp[now][j][k]+(k==0)*a[i].h);
                upd(dp[now^1][j][k],dp[now][j][k]+(j+k==sum[i-1])*a[i].h);
         
            }       
        now^=1;
    }
    int ans=1e9;
    For(j,1,sum[n]-1)
        For(k,1,sum[n]-j-1)
        {
 
            if(dp[now][j][k]>=1000)  continue;
            upd(ans,dp[now][j][k]*max(j,max(k,sum[n]-j-k)));
        }
    printf("%d",ans);
}

http://www.lydsy.com/JudgeOnline/problem.php?id=1934

最小割水題

不過建圖還是有點巧妙的

顯然的一個思路

對於期望1的人,向源點連,0的人向匯點,然後朋友之間連雙向

那麼這樣怎麼保證

比如說i和j

他們本身都期望0

但是j的邊被割掉了也就是投了1

而此時的i和j依然沒有連接S和E的路徑?

但是此時S或者E可到達i,而i可到達j

也就是說如果i和j要不產生貢獻,必須把i也割掉

所以可以保證正確性

 
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define For(i,j,k)  for(int i=j;i<=k;++i)
#define Dow(i,j,k)  for(int i=k;i>=j;--i)
#define ll long long
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9')t=t*10+c-48,c=getchar();
    return t*f;
}
int cnt=1,poi[200001],nxt[200001],head[200001],v[200001];
int dis[3001],cur[3001],n,m,S,E,x,y,q[3001];
inline void add(int x,int y)
{
    poi[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;v[cnt]=1;
    poi[++cnt]=x;nxt[cnt]=head[x];head[x]=cnt;v[cnt]=0;
}
inline bool bfs()
{
    For(i,1,E)  dis[i]=0,cur[i]=head[i];
    int l=1,r=1;
    q[1]=S;
    while(l<=r)
    {
        for(int i=head[q[l]];i;i=nxt[i])
            if(!dis[poi[i]]&&v[i])  dis[poi[i]]=dis[q[l]]+1,q[++r]=poi[i];
        ++l;
    }
    return dis[E]!=0;
}
inline int dfs(int x,int flow)
{
    if(x==E)    return flow;
    int used=0;
    for(int &i=cur[x];i;i=nxt[i])
        if(v[i]&&dis[poi[i]]==dis[x]+1)
        {
            int tmp=dfs(poi[i],min(flow-used,v[i]));
            v[i]-=tmp;v[i^1]+=tmp;used+=tmp;
            if(used==flow)  return used;    
        }
    dis[x]=-1;
    return used;
}
inline void dinic()
{
    int ans=0;
    while(bfs())    ans+=dfs(S,1e9);
    printf("%d\n",ans);
}
int main()
{
    n=read();m=read();
    S=n+1;E=S+1;
    For(i,1,n)  
    {
        if((read())==1) add(S,i);
        else    add(i,E);
    }
    For(i,1,m)
    {
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dinic();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章