加载中…

返回上一页

【比赛】暑假集训1

题面和题解的下载链接

A.玩游戏

极为无聊的一道题,只需要从 \(k\) 出发,寻找左边和右边能达到的最远距离,若等于1和n,有解;否则,无解.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 100001
using namespace std;
static inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
}
static inline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|48);
}
ll t,n,k,l,r;
ll a[maxn],sum[maxn];
bool fl;
int main()
{
	t=read();
	while(t--)
	{
        memset(sum,0,sizeof(sum));
		n=read();k=read();read();
        for(rll i=2;i<=n;i++) a[i]=read();
        for(rll i=k-1;i;i--) sum[i]=sum[i+1]+a[i+1];
        for(rll i=k+1;i<=n;i++) sum[i]=sum[i-1]+a[i];
        r=k+1;fl=0;
        for(rll j=k;j;j--)
        {
            while(sum[j]+sum[r+1]<=0&&r<n) r++;
            while(sum[j]+sum[r]>0) r--;
            if(r<k) {fl=1;break;}
        }
		if((!fl)&&r==n) puts("Yes");
		else puts("No");
	}
	return 0;
}

B.排列

一道 \(dp\) 好题.

\(dp[i][j][0/1]\) 为一个长度为 \(i\) 的序列,最多需要 \(j\) 次操作使得元素个数变为1的方案数.第三维中的0/1表示两边有无更大的数,0表示没有、1表示有.

那么 \(dp\) 状态转移方程即为:

\[dp[i][j][0]=\Sigma C^{k-1}_{i-1} \times dp[k-1][j-1][1] \times dp[i-k][j][0] \]

\[dp[i][j][1]=\Sigma C^{k-1}_{i-1} \times (dp[k-1][j][1] \times f[i-k][j-1][1]+dp[k-1][j-1][1] \times dp[i-k][j][1]-dp[k-1][j-1][1] \times dp[i-k][j-1][1]) \]

利用前缀和思想,

\[ans=\Sigma C^{i-1}_{n-1} \times (dp[i-1][k][0] \times dp[n-i][k][0]-dp[i-1][k-1][0] \times dp[n-i][k-1][0]) \]

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 1001
using namespace std;
static inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
}
static inline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|48);
}
ll n,k,p,ans;
ll dp[maxn][maxn][2];
ll c[maxn][maxn];
#define C(a,b) c[a][b]
// 用费马小求组合数会T且在模数非素数时会被卡.
// ll jc[maxn];
// static inline ll ksm(rll a,rll b)
// {
// 	rll ans=1;a%=p;
// 	for(rll i=b;i;i>>=1)
// 	{
// 		if(i&1) ans=ans*a%p;
// 		a=a*a%p;
// 	}
// 	return ans;
// }
// static inline ll C(rll n,rll m)
// {
// 	if(n<m) return 0;
// 	return jc[n]*ksm(jc[m],p-2)%p*ksm(jc[n-m],p-2)%p;
// }
int main()
{
	n=read();k=read();p=read();
	// jc[0]=1;for(rll i=1;i<maxn;i++) jc[i]=jc[i-1]*i%p;
	c[0][0]=1;for(rll i=1;i<=n;i++) { c[i][0]=1; for(rll j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%p; }
	if(k-1>=log2(n)) { puts("0"); return 0; }
	for(rll i=0;i<=k;i++) dp[0][i][0]=dp[0][i][1]=1;
	for(rll i=1;i<=n;i++)
		for(rll j=1;j<=k;j++)
			for(rll l=1;l<=i;l++)
			{
				dp[i][j][0]=(dp[i][j][0]+C(i-1,l-1)*dp[l-1][j-1][1]%p*dp[i-l][j][0]%p)%p;
				dp[i][j][1]=(dp[i][j][1]+C(i-1,l-1)*(dp[l-1][j][1]*dp[i-l][j-1][1]%p+dp[l-1][j-1][1]*dp[i-l][j][1]%p-dp[l-1][j-1][1]*dp[i-l][j-1][1]%p+p)%p)%p;
			}
	for(rll i=1;i<=n;i++) ans=(ans+C(n-1,i-1)*(dp[i-1][k][0]*dp[n-i][k][0]%p-dp[i-1][k-1][0]*dp[n-i][k-1][0]%p+p)%p)%p;
	write(ans);
	return 0;
}

C.最短路

二维最短路.

把每一条边都建一个反边,去跑二维Dijkstra.
\(dis[i][j]\) 为从点1沿正边到点i与沿反边到点j的距离之和.
那么 \(dis[n][n]\) 即为从点1沿正边到点n再沿正边回到点1的距离.

使用 \(\text{bitset}\) 维护即可.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 252
#define inf 4557430888798830399
using namespace std;
static inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
}
static inline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|48);
}
struct node
{
	ll x,y,dis;
	inline friend bool operator<(rg node a,rg node b)
	{
		return a.dis>b.dis;
	}
};
ll n,m;
ll a[maxn];
vector<ll> g[maxn],h[maxn];
bitset<maxn> fl[maxn][maxn];
ll dis[maxn][maxn];
priority_queue<node> que;
inline void dij()
{
	memset(dis,0x3f,sizeof(dis));
	dis[1][1]=a[1];que.push((node) { 1,1,a[1] });
	fl[1][1][1]=1;
	while(!que.empty())
	{
		rll x=que.top().x,y=que.top().y,d=que.top().dis;que.pop();
		if(x==n&&y==n) break;
		for(rll i=0;i<g[x].size();i++)
		{
			rll to=g[x][i],v=d;
			if(!fl[x][y][to]) v+=a[to];
			if(dis[to][y]>v)
			{
				fl[to][y]=fl[x][y];fl[to][y][to]=1;
				dis[to][y]=v;que.push((node) { to,y,v });
			}
		}
		for(rll i=0;i<h[y].size();i++)
		{
			rll to=h[y][i],v=d;
			if(!fl[x][y][to]) v+=a[to];
			if(dis[x][to]>v)
			{
				fl[x][to]=fl[x][y];fl[x][to][to]=1;
				dis[x][to]=v;que.push((node) { x,to,v });
			}
		}
	}
}
int main()
{
	n=read();m=read();
	for(rll i=1;i<=n;i++) a[i]=read();
	for(rll i=1,x,y;i<=m;i++) x=read(),y=read(),g[x].push_back(y),h[y].push_back(x);
	dij();
	write(dis[n][n]>=inf?-1:dis[n][n]);
	return 0;
}

D.矩形

显然用扫描线做比dfs要简单.

按照 \(x\) 排序,把 \(y\) 坐标加入线段树中,记录一下左右边界和其中有矩形的数量(1个还是多个)(color).然后从左往右扫一遍,查询左边界有没有矩形,再拿右边界更新就行了.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 100001
// #define x first
// #define y second
using namespace std;
static inline ll read()
{
	rll f=0,k=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') k=(k<<3)+(k<<1)+(ch^48),ch=getchar();
	return f?-k:k;
}
static inline void write(rll k)
{
	if(k<0) putchar('-'),k=-k;
	if(k>9) write(k/10);putchar(k%10|48);
}
struct node
{
	ll _x1,_y1,_x2,_y2;
	inline friend bool operator<(rg node x,rg node y)
	{
		return x._x1<y._x1;
	}
}a[maxn];
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	ll cnt/*id*/,pos;
	bool color/*0表示区间内只有一个矩形,1表示有多个*/,tag;
}t[maxn<<2];
ll n,ans;
ll f[maxn];
bool fl[maxn];
ll _x1,_y1,_x2,_y2,mx;
static inline ll find(rll k)
{
	if(k!=f[k]) f[k]=find(f[k]);
	return f[k];
}
static inline void pushup(rll rt)
{
	if(t[ls(rt)].cnt==t[rs(rt)].cnt)
	{
		t[rt].cnt=t[ls(rt)].cnt;
		t[rt].pos=t[ls(rt)].pos;
		t[rt].color=0;
	}
	else t[rt].color=1;
	if(t[ls(rt)].color||t[rs(rt)].color) t[rt].color=1;
}
static inline void pushdown(rll rt)
{
	if(!t[rt].tag) return;
	t[ls(rt)].tag=t[rs(rt)].tag=t[rt].tag;
	t[ls(rt)].cnt=t[rs(rt)].cnt=t[rt].cnt;
	t[ls(rt)].pos=t[rs(rt)].pos=t[rt].pos;
	t[rt].tag=0;
}
static inline void upd(rll rt,rll l,rll r,rll x,rll y,rll pos,rll v)
{
	if(x<=l&&r<=y)
		if(!t[rt].color)
		{
			if(t[rt].pos>pos) return;
			t[rt].tag=1;t[rt].pos=pos;t[rt].cnt=v;return;
		}
	pushdown(rt);
	rll mid=(l+r)>>1;
	if(x<=mid) upd(ls(rt),l,mid,x,y,pos,v);
	if(y>mid) upd(rs(rt),mid+1,r,x,y,pos,v);
	pushup(rt);
}
static inline void query(rll rt,rll l,rll r,rll x,rll y,rll pos,rll v)
{
	if(x<=l&&r<=y)
		if(!t[rt].color)
		{
			if(t[rt].pos>=pos) f[find(v)]=find(t[rt].cnt);
			return;
		}
	pushdown(rt);
	rll mid=(l+r)>>1;
	if(x<=mid) query(ls(rt),l,mid,x,y,pos,v);
	if(y>mid) query(rs(rt),mid+1,r,x,y,pos,v);
	pushup(rt);
}
int main()
{
	n=read();
	for(rll i=1;i<=n;i++) f[i]=i;
	for(rll i=1;i<=n;i++)
	{
		_x1=read();_y1=read();_x2=read();_y2=read();
		a[i]=(node){_x1,_y1,_x2,_y2};
		mx=max(mx,_y2);
	}
	sort(a+1,a+n+1);
	for(rll i=1;i<=n;i++)
		query(1,1,mx,a[i]._y1,a[i]._y2,a[i]._x1,i),
		upd(1,1,mx,a[i]._y1,a[i]._y2,a[i]._x2,i);
	for(rll i=1;i<=n;i++) if(find(i)==i) ans++;
	write(ans);
	return 0;
}

另附一份能A的暴力玄学代码,枚举20次停止,然后就过了???

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 100001
#define x first
#define y second
using namespace std;
static inline ll read()
{
	rll f=0,k=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') k=(k<<3)+(k<<1)+(ch^48),ch=getchar();
	return f?-k:k;
}
static inline void write(rll k)
{
	if(k<0) putchar('-'),k=-k;
	if(k>9) write(k/10);putchar(k%10|48);
}
ll n,ans;
ll f[maxn];
bool fl[maxn];
pair<pair<ll,ll>,pair<ll,ll> > mp[maxn];
static inline ll find(rll k)
{
	if(k!=f[k]) f[k]=find(f[k]);
	return f[k];
}
static inline bool chk(rll i,rll j)
{
	return !((mp[i].y.x<mp[j].x.x)||(mp[i].x.x>mp[j].y.x)||(mp[i].y.y<mp[j].x.y)||(mp[i].x.y>mp[j].y.y));
}
int main()
{
	n=read();
	for(rll i=1;i<=n;i++) f[i]=i;
	for(rll i=1;i<=n;i++)
	{
		mp[i].x.x=read();mp[i].x.y=read();
		mp[i].y.x=read();mp[i].y.y=read();
	}
	sort(mp+1,mp+n+1);
	for(rll i=1;i<=n;i++)
	{
		rll cnt=0;
		for(rll j=1;j<=n;j++)
		{
			if(cnt==20) break;
			if(i!=j)
				if(chk(i,j))
					f[find(i)]=find(j);cnt++;
		}
	}
	for(rll i=1;i<=n;i++) if(!fl[find(i)]) fl[find(i)]=1,ans++;
	write(ans);
	return 0;
}
posted @ 2022-08-11 22:13  1Liu  阅读(60)  评论(1)    收藏  举报