1004 Vacation
二分最终时间,然后从第一辆车开始递推求出每辆车的最终位置。复杂度为 O ( n log C ) O(n\log C) O(nlogC)。
STD::把第 i i i辆车追上第 i + 1 i+1 i+1辆车当作一个事件,显然只有 n n n个事件,且第 i i i辆车追上第 i + 1 i+1 i+1辆车只可能会对第 i − 1 i-1 i−1辆车追上第 i i i辆车的时间产生影响,且时间一定是变小,因此可以维护车之间的距离和速度来计算事件发生时间,用堆来找出最早发生的事件,不停处理直到 0 0 0车通过停车线。复杂度为 O ( n log n ) O(n\log n) O(nlogn)。
UPD 发现有很多大佬写了 O ( n ) O(n) O(n)的做法,大概是这样:最终通过停止线的时候,一定是一个车后面堵着剩余所有的车,那么影响时间的就只有最前面这辆车,所以对于每一辆车,假设是它是和 0 0 0车堵在一起的最靠前的一辆车,那么可以计算出一个值,所有的车的计算值的最大值就是答案。
#include<bits/stdc++.h>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
#define INF 0x3f3f3f3f
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int n,l[maxn],s[maxn],v[maxn];
double pos[maxn];
int check(double t){
pos[n]=s[n]-v[n]*t;
for(int i=n-1;i>=0;i--){
double x=v[i]*t;
pos[i]=s[i]-x;
if(pos[i]<pos[i+1]+l[i+1]) pos[i]=pos[i+1]+l[i+1];
}
return pos[0]<0;
}
int main() {
ios_base::sync_with_stdio(false);cin.tie(0);
while(cin>>n)
{
for (int i=0;i<=n;i++) scanf("%d",&l[i]);
for (int i=0;i<=n;i++) scanf("%d",&s[i]);
for (int i=0;i<=n;i++) scanf("%d",&v[i]);
double L=0,R=1e9,mid;
while(R-L>1e-6)
{
mid = (L+R)/2;
if (check(mid)) R=mid;
else L=mid;
}
cout<<fixed<<setprecision(10)<<mid<<endl;
}
return 0;
}
1005 Path
给一个图,删去一条边的代价为边权,用最小的代价和使最短路增加。
solutiion:跑一遍最短路,然后用d[e.v] - d[u] = e.w的边建图,求最小割。
#include<bits/stdc++.h>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
const long long INF=1e18;
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int vis[maxn],m,n;
ll d[maxn];
class Graph
{
private:
int s,t;
int Head[maxn];
int Next[maxn];
ll cnt;
ll V[maxn];
ll W[maxn];
ll Depth[maxn];
public:
void init(int nn,int ss,int tt)//初始化
{
n=nn;
s=ss;
t=tt;
cnt=-1;
memset(Head,-1,sizeof(Head));
memset(Next,-1,sizeof(Next));
return;
}
void _Add(int u,int v,ll w)
{
++cnt;
Next[cnt]=Head[u];
V[cnt]=v;
W[cnt]=w;
Head[u]=cnt;
}
void Add_Edge(int u,int v,ll w)//加边,同时加正向和反向的
{
_Add(u,v,w);
_Add(v,u,0);
}
ll dfs(int u,ll dist)
{
//cout<<"Dfs:"<<u<<' '<<dist<<endl;
if (u==t)
return dist;
for (int i=Head[u];i!=-1;i=Next[i])
{
if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))
{
ll di=dfs(V[i],min(dist,W[i]));
if (di>0)
{
W[i]-=di;
W[i^1]+=di;
return di;
}
}
}
return 0;
}
int bfs()
{
//cout<<"Bfs.begin:"<<endl;
queue<ll> Q;
while (!Q.empty())
Q.pop();
memset(Depth,0,sizeof(Depth));
Depth[s]=1;
Q.push(s);
do
{
int u=Q.front();
//cout<<"u:"<<u<<endl;
Q.pop();
for (int i=Head[u];i!=-1;i=Next[i])
{
if ((W[i]>0)&&(Depth[V[i]]==0))
{
Depth[V[i]]=Depth[u]+1;
Q.push(V[i]);
}
}
}
while (!Q.empty());
//cout<<"Bfs.end"<<endl;
if (Depth[t]>0)
return 1;
return 0;
}
ll Dinic()
{
ll Ans=0;
while (bfs())
{
while (ll d=dfs(s,INF))
Ans+=d;
}
return Ans;
}
};
struct node{
int v;
ll w;
node(int v=0,ll w=0):v(v),w(w){};
bool operator <(const node &rhs)const{
return w>rhs.w;
}
};
vector<node> G[maxn];
void init(){
cin>>n>>m;
for (int i = 1; i<=1e4; i++) {
G[i].clear();
d[i] = INF;
}
memset(vis,0,sizeof vis);
int x,y;ll z;
for(int i=1;i<=m;i++) {
cin>>x>>y>>z;
G[x].push_back(node(y, z));
//G[y].push_back((node){x, z});
}
}
void dijkstra(){
priority_queue<node> q;
q.push(node(1,0));
d[1]=0;
while(!q.empty())
{
node top=q.top();q.pop();
int u = top.v;
if (vis[u]) continue;
vis[u]=1;
for(int i=0;i<G[u].size();i++){
node v=G[u][i];
if (d[v.v] > d[u] + v.w) {
d[v.v] = d[u] + v.w;
q.push(node(v.v, d[v.v]));
}
}
}
}
int main() {
//freopen("/Users/cumt27/Desktop/02.in.txt","r",stdin);
ios_base::sync_with_stdio(false);cin.tie(0);
int iCase;
cin >> iCase;
while(iCase--) {
init();
dijkstra();
if (d[n] == INF)
std::cout << "0\n";
else {
Graph gu;
gu.init(n,1,n);
for (int u = 1; u <= n; u++)
for (auto e : G[u])
if (d[e.v] - d[u] == e.w)
gu.Add_Edge(u, e.v, e.w);
std::cout << gu.Dinic() << '\n';
}
}
return 0;
}
1009 String
用
n
x
t
[
i
]
[
j
]
nxt[i][j]
nxt[i][j]表示i位置之后第一次出现j的位置.
对于每一个位置,贪心的从
a
a
a到
z
z
z枚举当前可填字母,如果满足条件,立刻填上该字母,然后填下一个位置。
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<string.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
const long long INF=1e18;
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int used[26], l[26], r[26];
int cnt[maxn][26], nxt[maxn][26];
int n, k;
char s[maxn], ans[maxn];
inline void init(){
n=strlen(s);
for(int i=0;i<26;i++)
cin>>l[i]>>r[i];
memset(cnt,0,sizeof cnt);
memset(nxt,0,sizeof nxt);
memset(used,0,sizeof used);
for(int i=n-1;i>=0;i--) {
for (int j = 0; j < 26; j++) {
nxt[i][j] = nxt[i + 1][j];
cnt[i][j] = cnt[i + 1][j] + (s[i] == 'a' + j);
}
nxt[i][s[i]-'a']=i;
}
}
int main() {
//freopen("/Users/cumt27/Desktop/02.in","r",stdin);
ios_base::sync_with_stdio(false);cin.tie(0);
while(cin>>s>>k){
init();
int last=-1;
for(int i = 0;i < k; i++){
int find=0;
for(int j = 0;j < 26; j++)
if(used[j]<r[j])
{
++used[j];
int flag=1,sum=0,pos=nxt[last+1][j];
if(pos<last) continue;//在这里wa了无数次,当遍历完这个字母时,nxt会跳回去
for(int p=0;p<26;p++){
if(cnt[pos+1][p] + used[p] < l[p]) flag=0;//剩下的无法满足左边界
sum+=max(l[p] - used[p],0);//剩下的必须要填的字母
}
if(sum > k-i-1) flag=0;
sum=0;
for(int p=0;p<26;p++)
sum+=min(cnt[pos+1][p],r[p]-used[p]);//剩下的能填的字母
if(sum < k-i-1) flag=0;
if (!flag) --used[j];
else {
ans[i] = 'a' + j;
find = 1;
last = pos;
break;
}
}
if(!find) {
printf("-1\n");
goto end;
}
}
ans[k]='\0';
printf("%s\n",ans);
end:;
}
return 0;
}