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();
}