1004 Vacation
二分最終時間,然後從第一輛車開始遞推求出每輛車的最終位置。複雜度爲。
STD::把第輛車追上第輛車當作一個事件,顯然只有個事件,且第輛車追上第輛車只可能會對第輛車追上第輛車的時間產生影響,且時間一定是變小,因此可以維護車之間的距離和速度來計算事件發生時間,用堆來找出最早發生的事件,不停處理直到車通過停車線。複雜度爲。
UPD 發現有很多大佬寫了的做法,大概是這樣:最終通過停止線的時候,一定是一個車後面堵着剩餘所有的車,那麼影響時間的就只有最前面這輛車,所以對於每一輛車,假設是它是和車堵在一起的最靠前的一輛車,那麼可以計算出一個值,所有的車的計算值的最大值就是答案。
#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
用表示i位置之後第一次出現j的位置.
對於每一個位置,貪心的從到枚舉當前可填字母,如果滿足條件,立刻填上該字母,然後填下一個位置。
#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;
}