T1 0 pts
T2 10pts
T3 0 pts
好文推荐
图论中的二分
关于一个图中是否存在负环
1383: 小奇挖矿
___可以发现,当前的决策只对后面的开采有影响,且剩余耐久度与之后的开采收益成正比.
___如果倒着考虑这个问题,得出i-n的星球"1"耐久度所能获得的最大收益,从后往前dp,得出最大值最后乘w就是答案
考试技巧:zz的我懒得打暴力,结果dp写挂了……下次还是打包里吧,毕竟
** 绵阳市第三医院委提醒您:骗分千万条,暴力第一条,代码不规范,欧阳两行泪 **
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
#define N 100001
using namespace std;
double k,c,ans;
int n,w;
int op[N],a[N];
int main()
{
//freopen("input.txt","r",stdin);
scanf("%d%lf%lf%d",&n,&k,&c,&w);
rep(i,1,n)
scanf("%d%d",&op[i],&a[i]);
k=1-0.01*k,c=1+0.01*c;
dwn(i,n,1)
{
if(op[i]==1)
ans=max(ans,ans*k+a[i]);
else
ans=max(ans,ans*c-a[i]);
}
printf("%.2f",ans*w);
return 0;
}
1384: 小奇的数列
90pts 做法(前缀和+抽屉原理优化)
- 抽屉原理:如果询问的区间长度>=mod的话,一定有两个前缀和相减等于0,那么直接输出0即可
考试技巧:
我写的10 pts没加任何优化……抽屉原理送您80pts
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define inf 1000000000
using namespace std;
ll read()
{
ll 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-'0';ch=getchar();}
return x*f;
}
int n,m;
ll sum[500005];
int main()
{
freopen("input.txt","r",stdin);
scanf("%d%d",&n,&m);
rep(i,1,n)
sum[i]=sum[i-1]+read();
int l,r,mod;
rep(i,1,m)
{
l=read(),r=read(),mod=read();
if(r-l+1>mod)puts("0");//抽屉原理
else
{
int ans=mod;//相当于赋了一个极大值
rep(i,l,r)
rep(j,i,r)
ans=min((int)((sum[j]-sum[i-1])%mod),ans);
//强行转int
printf("%d\n",ans);
}
}
return 0;
}
1385: 小奇回地球
二分 && dfs反向染色 && SPFA+判负环
解析
1.跑有负边图的最短路只能SPFA。
2.由于t和答案同增同减,具有单调性。我们可以二分t来取符合条件的最小距离。
3.问题出在对负环的处理上。一开始想的是,有负环直接判不合法。然而如果通过负环不能到达n号点,这个负环实际上可以忽略。所以开头建反边,从n跑dfs看能到达哪些点,只对这些点跑最短路即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int ans,n,m,cnt,mid;
int head[10000],used[105],dis[105],mark[105];
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-'0';ch=getchar();}
return x*f;
}
struct node{
int v,w,nxt;
}e[10000];
vector<int>G[105];
void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].nxt=head[u];
e[cnt].w=w;
head[u]=cnt;
}
int SPFA()
{
memset(used,0,sizeof(used));
rep(i,1,n)dis[i]=INT_MAX;
used[1]=1;
queue<int>Q;
Q.push(1);
dis[1]=0;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(used[u]>n)
return false;//负环
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(!mark[v])continue;
int dist=e[i].w+mid;//要加上偏移量
if(dis[v]>dis[u]+dist)
{
dis[v]=dis[u]+dist;
used[v]++;
Q.push(v);
}
}
}
if(dis[n]>=0 && dis[n]!=INT_MAX)
return true;
else
return false;
}
void DFS(int cur)
{
mark[cur]=1;
for(int i=0;i<G[cur].size();i++)
{
if(mark[G[cur][i]])continue;
DFS(G[cur][i]);
}
}
int main()
{
freopen("input.txt","r",stdin);
int T;
T=read();
while(T--)
{
cnt=0;ans=-1;
memset(head,0,sizeof(head));
memset(e,0,sizeof(e));
memset(mark,0,sizeof(mark));
int l=-INT_MAX,r=INT_MAX;
n=read(),m=read();
rep(i,1,m)
{
int x,y,z;
x=read(),y=read(),z=read();
add(x,y,z);
G[y].push_back(x);
}
l=-100000,r=100000;
DFS(n);
while(l<=r)
{
mid=(l+r)>>1;
if(SPFA())
{
ans=dis[n];
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
rep(i,1,n)G[i].clear();
}
return 0;
}