题意:张3要求所有人跑步,有一条无限长跑道,每个人可以规定自己跑步的方向,起点,跑步起止时间。另外每个人跑步的速度都是1m/s。张3最后从监控人员哪里得到了n个报告,每个报告给出了某人在某一时候所在的位置,问跑步的最少可能人数是多少。
思路:
以时间和位置为横纵坐标,将这n个报告对应的点画在坐标系上。因为每个人跑步的速度都是1m/s,所以如果两个点所在直线斜率为1或-1,那么他们就有可能是同一个人,换个角度来说就是斜率为±1的直线上的所有点 可能是一个人跑出来的(而且最少一个人)。那么这个问题就转化成用最少的直线(斜率为±1)覆盖所有所有的点。我们将这个图旋转45°,就是二分图中棋盘问题的模型了。
然后用最大流跑二分图最大匹配 O ( m n ) O(m\sqrt{n} ) O(mn):通过点建立“横坐标”和“纵坐标”之间的连接,然后建立源点到“横坐标”、“纵坐标”到汇点的连接。
//加上源点和汇点,点数上限为2e5+2
//边数上限为3e5*3
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int manx=2e5+10;
const int manx2=6e5+10;
int cou,s,t;
int deep[manx],X[manx],Y[manx],x[manx],y[manx];
int head[manx],cur[manx];
int flow[manx];
struct node
{
int e,bf,w;
}edge[manx2];
inline void add(int s,int e,int w)
{
edge[++cou]=node{e,head[s],w};
head[s]=cou;
}
int bfs(int n)
{
for(int i=0;i<=n;i++)cur[i]=head[i],deep[i]=-1;
queue<int>qu;
qu.push(s);
deep[s]=0;
while(!qu.empty())
{
int now=qu.front();
qu.pop();
for(int i=head[now];~i;i=edge[i].bf)
{
int net=edge[i].e;
if(edge[i].w>0&&deep[net]==-1)
{
deep[net]=deep[now]+1;
qu.push(net);
}
}
}
return deep[t]!=-1;
}
//因为把flow上限写成2,T到飞起
int dfs(int now=s,int flow=1e8)
{
if(now==t)
return flow;
int ans=0;
for(int i=cur[now];~i&&flow;i=edge[i].bf)
{
cur[now]=i;
int net=edge[i].e;
if(edge[i].w>0&&deep[net]==deep[now]+1)
{
int temp=dfs(net,min(flow,edge[i].w));
flow-=temp,ans+=temp;
edge[i].w-=temp;
edge[i^1].w+=temp;
}
}
return ans;
}
int Dinic(int n)
{
int ans=0;
while(bfs(n))
ans+=dfs();
return ans;
}
int main()
{
int T,n,x2,t2;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
pair<int,int>point[manx];
for(int i=0;i<n;++i)
{
scanf("%d%d",&t2,&x2);
int l=x2+t2,r=x2-t2;
point[i].first=l,point[i].second=r;
}
sort(point,point+n);
n=unique(point,point+n)-point;//去重点
for(int i=0;i<n;i++)
{
X[i]=x[i]=point[i].first;
Y[i]=y[i]=point[i].second;
}
//sort(X,X+n);
sort(Y,Y+n);
int cou1=unique(X,X+n)-X;
int cou2=unique(Y,Y+n)-Y;
s=cou1+cou2,t=s+1;
cou=-1;
for(int i=0;i<=t;++i)head[i]=-1;
for(int i=0;i<cou1;++i)//建立源点到“横坐标”、“纵坐标”到汇点的连接
add(s,i,1),add(i,s,0);
for(int i=0;i<cou2;++i)
add(i+cou1,t,1),add(t,i+cou1,0);
for(int i=0;i<n;++i)
{//建立“横坐标”和“纵坐标”之间的连接
int x1=lower_bound(X,X+cou1,x[i])-X;
int y1=lower_bound(Y,Y+cou2,y[i])-Y+cou1;
add(x1,y1,1);
add(y1,x1,0);
}
printf("%d\n",Dinic(t));
}
return 0;
}
设dp[i]表示前i个单词的"almost-equal"的个数
str[i]==str[i-1]时,dp[i]=dp[i-1];
str[i]!=str[i-1]时,dp[i]=dp[i-1]+dp[i-2]
#include
#include
#include
//#define int long long
using namespace std;
const int mod=1e9+7;
const int manx=1e5+7;
string a[manx];
signed main()
{
int t,n,dp[manx];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
cin>>a[i];
dp[1]=dp[2]=1;
if(a[1]!=a[2])dp[2]=2;
for(int i=3;i<=n;i++)
if(a[i]!=a[i-1])
dp[i]=(dp[i-1]+dp[i-2])%mod;
else dp[i]=dp[i-1];
printf("%d\n",dp[n]);
}
return 0;
}