POI2014(未完待续)

Solar Panels:

简单题,直接分块对每种数判断是否合法就行了。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
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<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int main()
{
    int T=read();
    while(T--)
    {
        int l1=read(),r1=read(),l2=read(),r2=read();
        int l=max(l1,l2),r=min(r1,r2);
        if(l<=r){printf("%d\n",r);continue;}
        if(l1>l2)swap(l1,l2),swap(r1,r2);
        int pos,ans=1;
        for(int i=l1;i<=r1;i=pos+1)
        {
            int t1=l2/i,t2=r2/i,nl=min(r1,l2/(l2/i)),nr=min(r1,r2/(r2/i));
            pos=min(nl,nr);
            if(l2%i==0||t1!=t2)ans=i;
            if(l2%pos==0||t1!=t2)ans=pos;
        }
        if(ans!=1){printf("%d\n",ans);continue;}
        int cnt=0;
        for(int i=1;i<l1;i=pos+1)
        {
            cnt++;
            int tl1=l1/i,tr1=r1/i,nl1=min(l1-1,l1/(l1/i)),nr1=min(l1-1,r1/(r1/i));
            int tl2=l2/i,tr2=r2/i,nl2=min(l1-1,l2/(l2/i)),nr2=min(l1-1,r2/(r2/i));
            pos=min(min(nl1,nl2),min(nr1,nr2));
            if((l1%i==0||tl1!=tr1)&&(l2%i==0||tl2!=tr2))ans=i;
            if((l1%pos==0||tl1!=tr1)&&(l2%pos==0||tl2!=tr2))ans=pos;
        }
        printf("%d\n",ans);
    }
}

Little Bird:

考虑最简单的DP:
f i = f j ( D i &lt; D j ) f_i=f_j(D_i&lt;D_j) fi=fj(Di<Dj) f i = f j + 1 ( D i &gt; = D j ) f_i=f_j+1(D_i&gt;=D_j) fi=fj+1(Di>=Dj)
看上去像单调队列的样子,但是无法解决括号内的限制。
但是由于后面的式子只会使答案+1,所以可以直接维护一个 f f f单调递增的单调队列,这样就可以保证队头的一定是最优的之一。
如果 f f f相等就保留 D D D大的。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=2147483647;
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<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int Q,n,k,D[Maxn],q[Maxn],head,tail,f[Maxn];
int main()
{
    n=read();
    for(int i=1;i<=n;i++)D[i]=read();
    Q=read();
    while(Q--)
    {
        k=read();
        head=tail=1;
        q[1]=1;f[1]=0;
        for(int i=2;i<=n;i++)
        {
            while(head<=tail&&q[head]<i-k)head++;
            f[i]=f[q[head]]+(D[q[head]]<=D[i]);
            while(head<=tail&&(f[q[tail]]>f[i]||(f[q[tail]]==f[i]&&D[i]>=D[q[tail]])))tail--;
            q[++tail]=i;
        }
        printf("%d\n",f[n]);
    }
}

Card:

水题,线段树直接维护区间内两个端点四种选择情况是否可行即可。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=200010;
const int inf=2147483647;
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<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,q,v[Maxn][2];
bool c[Maxn<<2][2][2];
void up(int x,int lc,int rc,int p)
{
	for(int i=0;i<2;i++)
	for(int j=0;j<2;j++)
	c[x][i][j]=false,
	c[x][i][j]|=
	(
	((v[p][0]<=v[p+1][0])&c[lc][i][0]&c[rc][0][j])|
	((v[p][0]<=v[p+1][1])&c[lc][i][0]&c[rc][1][j])|
	((v[p][1]<=v[p+1][0])&c[lc][i][1]&c[rc][0][j])|
	((v[p][1]<=v[p+1][1])&c[lc][i][1]&c[rc][1][j])
	);
}
void w(int x,int l,int r)
{
	if(l==r)
	{
		c[x][0][0]=c[x][1][1]=true;
		c[x][0][1]=c[x][1][0]=false;
		return;
	}
	int mid=l+r>>1,lc=(x<<1),rc=((x<<1)|1);
	w(lc,l,mid),w(rc,mid+1,r);
	up(x,lc,rc,mid);
}
void modify(int x,int l,int r,int p)
{
	if(l==r)return;
	int mid=l+r>>1,lc=(x<<1),rc=((x<<1)|1);
	if(p<=mid)modify(lc,l,mid,p);
	else modify(rc,mid+1,r,p);
	up(x,lc,rc,mid);
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)v[i][0]=read(),v[i][1]=read();
	w(1,1,n);
	q=read();
	while(q--)
	{
		int x=read(),y=read();
		swap(v[x][0],v[y][0]),swap(v[x][1],v[y][1]);
		modify(1,1,n,x),modify(1,1,n,y);
		if(c[1][0][0]||c[1][0][1]||c[1][1][0]||c[1][1][1])puts("TAK");
		else puts("NIE");
	}
}

Bricks:

先把最多的颜色找出来,然后把首颜色插到前面的一段空,把尾颜色插到后面的一段空,然后再把剩下的颜色插空。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=2147483647;
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<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int A[10],lA=0;
void write(int x)
{
	if(!x){putchar('0');return;}
	lA=0;while(x)A[++lA]=x%10,x/=10;
	for(int i=lA;i;i--)putchar(A[i]+48);
}
int n,Start,End,lst[Maxn],nxt[Maxn],col[Maxn],st,ed,tot=0,cnt[Maxn],tcnt[Maxn],ans[Maxn],la=0;
struct C{int x,id;}a[Maxn];
bool cmp(C a,C b)
{
	if(a.x!=b.x)return a.x>b.x;
	if(a.id!=Start&&a.id!=End&&b.id!=Start&&b.id!=End)return a.id<b.id;
	if(a.id==Start&&b.id==End)return true;
	if(a.id==End&&b.id==Start)return false;
	if(a.id==Start||a.id==End)return false;
	return true;
}
void insert(int x,int y,int z)
{
	col[++tot]=z;
	if(x!=-1)nxt[x]=tot;else st=tot;
	if(y!=-1)lst[y]=tot;else ed=tot;
	lst[tot]=x,nxt[tot]=y;
}
void work(int pos)
{
	for(int i=1;i<=n;i++)
	{
		if(!a[i].x)continue;
		for(int j=1;j<=a[i].x;j++)
		{
			if(pos==ed)pos=st;
			int p=nxt[pos];
			insert(pos,nxt[pos],a[i].id);
			pos=p;
		}
		a[i].x=0;
	}
}
bool check()
{
	if(ans[1]!=Start)return false;
	if(ans[la]!=End)return false;
	for(int i=1;i<=la;i++)
	{
		tcnt[ans[i]]++;
		if(i>1&&ans[i]==ans[i-1])return false;
	}
	for(int i=1;i<=n;i++)if(cnt[i]!=tcnt[i])return false;
	return true;
}
int main()
{
	n=read(),Start=read(),End=read();
	bool flag=false;
	for(int i=1;i<=n;i++)a[i].x=cnt[i]=read(),a[i].id=i;
	if(a[Start].x<a[End].x)swap(Start,End),flag=true;
	sort(a+1,a+1+n,cmp);

	for(int i=1;i<=a[1].x;i++)insert((i==1)?(-1):i-1,-1,a[1].id);
	a[1].x=0;
	
	if(Start==End)
	{
		if(a[1].id==Start)work(st);
		else
		{
			st=tot+1;
			for(int i=1;i<=n;i++)
			if(a[i].id==Start)
			{
				int p=tot,t=a[i].x;a[i].x=0;
				for(int j=1;j<t;j++)insert(lst[j],j,Start);
				insert(p,-1,Start);
				work(t-1);
				break;
			}
		}
	}
	
	else
	{
		if(a[1].id!=Start&&a[1].id!=End)
		{
			int ppp;
			for(int i=1;i<=n;i++)
			if(a[i].id==Start)
			{
				int t=a[i].x;ppp=t,a[i].x=0;
				for(int j=1;j<=t;j++)insert(lst[j],j,Start);
				break;
			}
			for(int i=1;i<=n;i++)
			if(a[i].id==End)
			{
				int p=ed,t=a[i].x;a[i].x=0;
				for(int j=1;j<=t;j++)insert(p,nxt[p],End),p=lst[p];
				break;
			}
			work(ppp);
		}
		else
		{
			int p=tot;
			for(int i=1;i<=n;i++)
			if(a[i].id==End)
			{
				int t=a[i].x;a[i].x=0;
				for(int j=1;j<=t;j++)insert(p,nxt[p],End),p=lst[p];
				break;
			}
			work(1);
		}
	}
	
	for(int i=st;i!=-1;i=nxt[i])ans[++la]=col[i];
	if(!check())return printf("0"),0;
	if(flag)
	{
		for(int i=1;i<=(la>>1);i++)swap(ans[i],ans[la-i+1]);
	}
	for(int i=1;i<la;i++)write(ans[i]),putchar(' ');
	printf("%d",ans[la]);
}

Salad Bar:

O ( n ) O(n) O(n)预处理出每个位置向左向右最多延伸到哪里,然后用单调栈完成求答案。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=2147483647;
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<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,nxt[Maxn],pos[Maxn<<1],p[2][Maxn],fir[Maxn<<1],sta[Maxn],top=0;
char s[Maxn];
void work(int o)
{
	for(int i=-n;i<=n;i++)pos[i+n]=fir[i+n]=-1;
	int t=n,sum=n;
	for(int i=1;i<=n;i++)
	{
		int x=((s[i]=='j')?-1:1);
		sum+=x;nxt[i]=-1;
		if(pos[sum]==-1)fir[sum]=i;
		else nxt[pos[sum]]=i;
		pos[sum]=i;
	}
	sum=n;
	for(int i=1;i<=n;i++)
	{
		int x=((s[i]=='j')?-1:1);
		sum+=x;
		if(x==1)
		{
			if(fir[-1+t]==-1)p[o][i]=n;
			else p[o][i]=fir[-1+t]-1;
		}
		fir[sum]=nxt[i];t+=x;
	}
}
int main()
{
	n=read();
	scanf("%s",s+1);
	work(0);
	for(int i=1;i<=(n>>1);i++)swap(s[i],s[n-i+1]);
	work(1);
	for(int i=1;i<=(n>>1);i++)swap(p[1][i],p[1][n-i+1]);
	for(int i=1;i<=n;i++)if(p[1][i])p[1][i]=n-p[1][i]+1;
	int ans=0;
	for(int i=n;i;i--)
	{
		if(s[n-i+1]=='p')
		{
			while(top&&p[1][i]<p[1][sta[top]])top--;
			sta[++top]=i;
		}
		int l=1,r=top;bool flag=false;
		while(l<=r)
		{
			int mid=l+r>>1;
			if(sta[mid]<=p[0][i]){r=mid-1;flag=true;}
			else l=mid+1;
		}
		if(flag)ans=max(ans,sta[r+1]-i+1);
	}
	printf("%d",ans);
}

Rally:

这题好神……
先给把最长路的起点终点固定,新建源点 S S S和汇点 T T T S S S连向所有点,所有点连向 T T T。设 f x f_x fx S S S x x x的最长路, g x g_x gx x x x T T T最长路,把每条边的边权设为 f x + 1 + g y f_x+1+g_y fx+1+gy,那么一个割集中的边权最大值就是最长路。
枚举删哪一个点,考虑如何维护这个割集,使得割集中的边权不会受被删点的影响。删去 x x x后,有三种边是不会受影响的的, S S S到拓扑序在 x x x之前的点的边,拓扑序在 x x x后到 T T T的边,和拓扑序在 x x x之前的点到拓扑序在 x x x后的点边。
所以可以按照拓扑序逐个枚举被删的点,用一个堆维护割集即可。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const int Maxm=1000010;
const int inf=2147483647;
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<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,deg[Maxn],a[Maxn],la=0,f[Maxn],g[Maxn],ans1,ans2=inf;
vector<int>p1[Maxn],p2[Maxn];
struct Heap
{
    priority_queue<int>q1,q2;
    int Top()
    {
        while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();
        return q1.top();
    }
    void Delete(int x){q2.push(x);}
    void Push(int x){q1.push(x);}
}Q;
int main()
{
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        p1[x].push_back(y);deg[y]++;
        p2[y].push_back(x);
    }
    queue<int>q;
    for(int i=1;i<=n;i++)if(!deg[i])q.push(i);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        a[++la]=x;
        for(int i=0;i<p1[x].size();i++)
        {
            int y=p1[x][i];
            deg[y]--;
            if(!deg[y])q.push(y);
        }
    }
    for(int i=1;i<=n;i++)
    for(int j=0;j<p1[a[i]].size();j++)
    f[p1[a[i]][j]]=max(f[p1[a[i]][j]],f[a[i]]+1);
    for(int i=n;i;i--)
    for(int j=0;j<p2[a[i]].size();j++)
    g[p2[a[i]][j]]=max(g[p2[a[i]][j]],g[a[i]]+1);
    for(int i=1;i<=n;i++)Q.Push(g[i]);
    for(int i=1;i<=n;i++)
    {
        int x=a[i];
        for(int j=0;j<p2[x].size();j++)Q.Delete(f[p2[x][j]]+g[x]+1);
        Q.Delete(g[x]);
        if(Q.Top()<ans2)ans2=Q.Top(),ans1=x;
        for(int j=0;j<p1[x].size();j++)Q.Push(f[x]+g[p1[x][j]]+1);
        Q.Push(f[x]);
    }
    printf("%d %d",ans1,ans2);
}

Ant colony:

树形DP水题,每个点记录合法范围即可。

代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=1000000000;
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<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,k,a[Maxn],X,Y,L[Maxn],R[Maxn],d[Maxn];
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y)
{
    int t=++len;
    e[t].y=y;e[t].next=last[x];last[x]=t;
}
void dfs(int x,int fa)
{
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa)continue;
        if((LL)L[x]*(d[x]-1)>inf)L[y]=inf+1;
        else L[y]=L[x]*(d[x]-1);
        if((LL)R[x]*(d[x]-1)+max(d[x]-2,0)>inf)R[y]=inf;
        else R[y]=R[x]*(d[x]-1)+max(d[x]-2,0);
        dfs(y,x);
    }
}
int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;i++)a[i]=read();
    sort(a+1,a+1+m);
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();d[x]++,d[y]++;
        if(i==1)X=x,Y=y;
        ins(x,y),ins(y,x);
    }
    L[X]=R[X]=L[Y]=R[Y]=k;
    dfs(X,Y),dfs(Y,X);
    LL ans=0;
    for(int i=1;i<=n;i++)
    if(d[i]==1)
    {
        if(L[i]==inf+1)continue;
        int l,r,ll,rr;
        l=1,r=m;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(a[mid]>=L[i])r=mid-1;
            else l=mid+1;
        }
        ll=r+1;
        l=1,r=m;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(a[mid]<=R[i])l=mid+1;
            else r=mid-1;
        }
        rr=l-1;
        ans+=((LL)rr-ll+1);
    }
    ans*=(LL)k;
    printf("%lld",ans);
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值