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