小A和uim之大逃离 II
这个问题就是一个裸的bfs,多了一个专移的方向而已,很简单
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
int n , m , xx[5] = { 1 , -1 , 0 , 0 }, yy[5] = { 0, 0 , 1 , -1 }, vis[1999][1999][2];
char a[1999][1999] ;
struct st{
int x ,y ,s ,f ;
};
queue < st > q ;
int bfs()
{
st o;
o.x = 1 , o.y = 1, o.s = 0 ,o.f = 0 ;
st o2;
o2.x = 1 , o2.y = 1, o2.s = 0 ,o2.f = 1 ;
vis[1][1][0] = 1;vis[1][1][1] = 1;
q.push (o) ;
q.push (o2);
while(!q.empty ()){
st w = q.front ();q.pop ();
//printf("%d %d %d %d\n",w.x,w.y,w.s,w.f);
for(int i = 0 ; i <= 4 ; i++){
if(i == 4 && w.f) continue;
st tmp;
tmp.x = w.x + xx[i];
tmp.y = w.y + yy[i];
tmp.s = w.s + 1;
if(i == 4) tmp.f = 1;
else tmp.f = w.f;
if(tmp.x>n||tmp.x<1||tmp.y<1||tmp.y>m) continue ;
if(a[tmp.x][tmp.y] == '.'){
if(!vis[tmp.x][tmp.y][tmp.f]){
vis[tmp.x][tmp.y][tmp.f] = 1;
if(tmp.x == n && tmp.y == m) {
printf("%d",tmp.s); return 1;
}
//printf("%d %d %d %d\n",tmp.x,tmp.y,tmp.s,tmp.f);
q.push(tmp);
}
}
}
}
return 0;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&xx[4],&yy[4]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >> a[i][j];
if(!bfs()) printf("-1");
return 0;
}
松江1843路
这个题就是一个模拟题
因为最两面的无论在哪一定要走
所以可以用较小的人数抵消,最后的位置就是最优的位置
#include<cstdio>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll n,l,x[199999],r[199999],ans;
int main()
{
scanf("%lld%lld",&l,&n);
for(ll i=1;i<=n;i++){
scanf("%lld%lld",&x[i],&r[i]);
}
ll h=1,t=n;
while(t>h){
ll w=min(r[t],r[h]);
r[t]-=w;
r[h]-=w;
ans+=w*(x[t]-x[h]);
if(!r[t])t--;
if(!r[h])h++;
}
printf("%lld",ans);
}
小A的糖果
又一道模拟题
就枚举糖果,看邻近的是否小于x,大于就吃掉,优先吃后面的,因为前面的已经优化过了。
#include<cstdio>
using namespace std;
long long n,a[199999],ans,m;
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(long long i=1;i<=n;i++)
if(a[i]+a[i+1]>m)
{
long long w=a[i]+a[i+1]-m;ans+=w;
if(a[i+1]>=w) a[i+1]-=w;
else if(a[i+1]<w) a[i]-=w-a[i+1],a[i+1]=0;
}
printf("%lld",ans);
}
跑路
就是一个dp啊,题解上还扯什么倍增,吓得我都不敢做了,这题跟倍增毛线关系都没有。。。。
dp[i][j][k]表示j到k 2^i的距离能不能到,很明显
如果j到k 2^i-1的距离能到,且k到q 2^i-1的距离也能到,那么j到q 2^i也能到
那么动态转移方程就出来了
dp[i][j][q]=dp[i-1][j][k]&dp[i-1][k][q];
接下来跑最短路就行了。
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
int n,m;long long a[1999][1999];bool dp[66][66][66];
int main()
{
scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)a[i][j]=65;
while(m--){
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1;
dp[0][x][y]=1;
}
for(int i=1;i<=64;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
for(int q=1;q<=n;q++){
if(dp[i-1][j][k]&&dp[i-1][k][q])
dp[i][j][q]=1,a[j][q]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++){
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
}
printf("%lld",a[1][n]);
}
hdu 手机的生产
思路
找规律可以发现,只有表达式的话,fork()会产生3台手机,fork()fork()会产生4台手机,fork()fork()fork会产生5台手机……依次类推。
那么我们可以用|把若干个连续的块分割开,每个长度为x的块会产生x−1个结果为0的表达式,1个结果为1的表达式,那么我们可以从右边往左边递推,假设共tot个块,可以得到f[i]=[i,tot]段块产生的手机个数,容易得到DP方程:
f[i]=(num[i]−1)f[i+1]+1,num[i]=第i段连续的$的长度
#include <cstdio>
using namespace std;
char s[6];
int a[99999]={0,1},f[99999],now=1;
int mod=998244353;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%s",s);
if(s[0]=='&') a[now]++;
else a[++now]=1;
}
for(int i=now;i>=0;i--)
f[i]=(1ll*f[i+1]*a[i+1]+1)%mod;
printf("%d",f[0]);
}
uoj 赴京赶考
有人说:
对于(ai,bi),若ai+1≠ai,则无论bi取何值,显然(ai,bi)到(ai+1,bi)都是需要花费1单位时间的。因此我们可以在x维度和y维度分别定义两种边:若ai≠ai+1,则ai到ai+1的距离就是1,否则为0。y维度亦然。
因此我们可以将x坐标和y坐标分块处理,得到每个维度上的边权的前缀和。然后根据x维度直接从xs走到xt、x维度从xs穿越边界走到xt、y维度直接从ys走到yt、y维度从ys穿越走到yt这四种情况进行讨论,得到最终的最短距离即可。复杂度O(n+m+q)
我也不知道为什么这样,就写了。。。。。。
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int n,m,t;
int a[199999],b[199999],sx[199999],sy[199999];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(i!=1)
sx[i]=sx[i-1]+(a[i]^a[i-1]);
}
for(int i=1;i<=m;i++) {
scanf("%d",&b[i]);
if(i!=1)
sy[i]=sy[i-1]+(b[i]^b[i-1]);
}
scanf("%d",&t);
while(t--){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int ans;
if(x2>=x1)
ans=min(sx[x2]-sx[x1],sx[n]-sx[x2]+sx[x1]+(a[n]^a[1]));
else ans=min(sx[n]-sx[x1]+sx[x2]+(a[n]^a[1]),sx[x1]-sx[x2]);
if(y2>=y1)
ans+=min(sy[y2]-sy[y1],sy[m]-sy[y2]+sy[y1]+(b[m]^b[1]));
else ans+=min(sy[m]-sy[y1]+sy[y2]+(b[m]^b[1]),sy[y1]-sy[y2]);
printf("%d\n",ans);
}
}
hdu 6119
小小粉丝度度熊
先把区间合并,在对他们补,找最大的连续区间
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
struct st{
ll l,r;
}a[199999];
int n;ll m;st ra[199999];int len[199999];
int cmp(const st a,const st b){
if(a.l<b.l) return 1;
return 0;
}
int main()
{
while(scanf("%d%lld",&n,&m)!=EOF)
{for(int i=1;i<=n;i++)
scanf("%lld%lld",&a[i].l,&a[i].r);
sort(a+1,a+n+1,cmp);
ra[1]=a[1];
int cnt=1;
for(int i=2;i<=n;i++)
if(ra[cnt].r+1>=a[i].l)
ra[cnt].r=max(ra[cnt].r,a[i].r);
else
ra[++cnt]=a[i];
for(int i=1;i<cnt;i++)
len[i]=ra[i+1].l-ra[i].r-1;
int l=1,now=0;
ll ans=0;
for(int i=1;i<cnt;i++)
{
now+=len[i];
while(m<now)
now-=len[l++];
ans=max(ans,ra[i+1].r-ra[l].l+1+m-now);
}
ans=max(ans,ra[1].r-ra[1].l+1+m);
printf("%lld\n",ans);
}
}