CSP11

wlesq發表於2024-07-29

CSP11

T1

image

暴力
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back

// #pragma comment(linker, ¡°/STACK:512000000,512000000¡±) 
using namespace std;
const int N = 2e5+5,mod=1e9+7,inf=1e9;
int n,m,dis[N];bool vis[N];
vector <int> edge[N];
struct Node
{
	int dis,u;
	bool operator < (const Node& A)const
	{
		return dis>A.dis;
	}
};
int st,en;
void dij(int st)
{
	for(int i=1;i<=n;i++)dis[i]=1e9;
	priority_queue <Node> q;
	q.push({0,st});
	dis[st]=0;
	while(q.size())
	{
		int u=q.top().u;q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto to:edge[u])
		{
			if(vis[to])continue;
			if(dis[to]>dis[u]+1)
			{
				dis[to]=dis[u]+1;
				q.push({dis[to],to});
			}
		}
	}
}
inline ll dfs(const int u,const int step,const int tg)
{
	if(step>tg||(step==tg&&u!=en))return 0;//這兩個特判最佳化不少
	if(u==en)return step==tg;
	vis[u]=1;
	ll res=0;
	for(auto to:edge[u])
	{
		if(vis[to])continue;
		res=(dfs(to,step+1,tg)+res)%mod;
	}
	vis[u]=0;
	return res;
}
int main()
{
	speed();
//	freopen("Fate1.in","r",stdin);
//	 freopen("Fate9.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>m;
	cin>>st>>en;
	// cout<<"**********"<<endl;
	int u,v;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v;
		edge[u].pb(v);edge[v].pb(u);
	}
	dij(st);
	memset(vis,0,sizeof vis);
	int tg=dis[en]+1;
	cout<<dfs(st,0,tg);
	return 0;
}

我們其實沒必要\(dfs\)找一遍,其實可以直接\(BFS\),從起點開始,\(f\)表示最短路徑的數量,\(g\)表示最短路徑+1的數量
如何轉移?,設當前為\(u->to\),\(dis_u==dis_{to}則g_{u}+=f_{to}\)\(dis_{to}=dis_u+1,則g_{to}+=g_u,f_{to}+=f_u\)
注意順序一定不能換,否則\(g_u\)不上

點選檢視程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
//#define int long long
#define pb push_back
#define pii pair<int,int>
// #pragma comment(linker, ¡°/STACK:512000000,512000000¡±) 
using namespace std;
const int N = 2e5+5,mod=1e9+7,inf=1e9;
int n,m,dis[N],g[N],f[N],id[N];bool vis[N];
vector <int> edge[N];
vector <pii> G;
struct Node
{
	int dis,u;
	bool operator < (const Node& A)const
	{
		return dis>A.dis;
	}
};
int st,en;
void dij(int st)
{
	for(int i=1;i<=n;i++)dis[i]=1e9;
	priority_queue <Node> q;
	q.push({0,st});
	dis[st]=0;
	while(q.size())
	{
		int u=q.top().u;q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto to:edge[u])
		{
			if(vis[to])continue;
			if(dis[to]>dis[u]+1)
			{
				dis[to]=dis[u]+1;
				q.push({dis[to],to});
			}
		}
	}
}
// unordered_map <int,map<int,int>> dp;
// inline ll dfs(const int u,const int step,const int tg)
// {
// 	if(step>tg||(step==tg&&u!=en))return 0;
// 	if(u==en)return step==tg;
// 	if(dp[u][step])return dp[u][step];
// 	// cout<<step<<endl;
// 	vis[u]=1;
// 	ll res=0;
// 	for(auto to:edge[u])
// 	{
// 		if(vis[to])continue;
// 		res=(dfs(to,step+1,tg)+res)%mod;
// 	}
// 	vis[u]=0;
// 	return dp[u][step]=res;
// }
int main()
{
	speed();
//	freopen("Fate1.in","r",stdin);
//	 freopen("Fate9.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>m;
	cin>>st>>en;
	// cout<<"**********"<<endl;
	int u,v;G.pb({0,0});
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v;
		G.pb({u,v});
		edge[u].pb(v);edge[v].pb(u);
	}
	dij(st);
	memset(vis,0,sizeof vis);
	auto ans=[&](int st,int en)
	{
		queue <int> q;
		q.push(st);
		f[st]=1;
		// vis[st]=1;
		while(q.size())
		{
			int u=q.front();q.pop();
			// if(vis[u])continue;
			// vis[u]=1;
			for(auto to:edge[u])
			{
				if(dis[u]==dis[to])
				{
					g[u]+=f[to];g[u]%=mod;
					// q.push(to);
				}
			}
			for(auto to:edge[u])
			{
				if(dis[to]==dis[u]+1)
				{
					g[to]+=g[u];
					f[to]+=f[u];
					g[to]%=mod;f[to]%=mod;
					if(!vis[to])vis[to]=1,q.push(to);
				}
			}

		}
		return g[en];
	};
	ll p=ans(st,en);
	cout<<p<<endl;
	return 0;
}

T2

暴力

點選檢視程式碼
#include  <bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
int sum[N];
int n,a;
struct Fs
{
	int x,w,v;
	double dis;
}f[N];
bool cmp(Fs a,Fs b)
{
	return a.x<b.x;
}
bool cmpdis(Fs a,Fs b)
{
	return a.dis<b.dis;
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//	freopen("EVA1.in","r",stdin);
	cin>>n>>a;
	bool ev=1;
	for(int i=1;i<=n;i++)
	{
		cin>>f[i].w>>f[i].x>>f[i].v;
		if(i>1&&f[i].v!=f[1].v)ev=0;	
	}	
	if(ev)
	{
//		cout<<"****"<<endl;
		sort(f+1,f+1+n,cmp);
		for(int i=1;i<=n;i++)sum[f[i].x]+=f[i].w;
		for(int i=1;i<=f[n].x;i++)sum[i]+=sum[i-1];
		int ans=0;
		for(int i=1;i<=f[n].x;i++)
		{
			ans=max(ans,sum[min(i+a,f[n].x)]-sum[i-1]);
		}
		cout<<ans<<endl;
		return 0;
	}
//	for(int i=1;i<=n;i++)
//	cout<<"****"<<endl;
	int ans=0;
	for(double t=0.0001;t<=1;t+=0.0001)
	{
		for(int i=1;i<=n;i++)
		{
			f[i].dis=f[i].x+f[i].v*t;
		}
		sort(f+1,f+1+n,cmpdis);
		for(int i=1;i<=n;i++)sum[i]=sum[i-1]+f[i].w;
		int st=1;
		for(int i=1;i<=n;i=-~i)
		{
			while(f[i].dis-a>f[st].dis)st++;
			ans=max(ans,sum[i]-sum[st-1]);
		}
	}
	for(double t=0.001;t<=10;t+=0.02)
	{
		for(int i=1;i<=n;i++)
		{
			f[i].dis=f[i].x+f[i].v*t;
		}
		sort(f+1,f+1+n,cmpdis);
		for(int i=1;i<=n;i=-~i)sum[i]=sum[i-1]+f[i].w;
		int st=1;
		for(int i=1;i<=n;i=-~i)
		{
			while(f[i].dis-a>f[st].dis)st++;
			ans=max(ans,sum[i]-sum[st-1]);
		}
	}	
	cout<<ans;
	return 0;
}
/*
3 10
1 15 55
10 20 55
100 25 55
*/

正解是列舉每一條魚,設為\(i\)作為左端點(一定是最優的),透過相對速度,算出每一條魚對它的貢獻\(l_t,r_t\),進行差分即可
一些細節問題,
精度問題
還有判斷\(r\)是負數的情況不能要
速度相等的情況要注意
由於精度問題\(l,r\)可能要互換位置,先要換位置,再判斷是否\(r<0\)
關於差分時,右端點\(r\)要加上一個\(eps\),就是為了先讓魚進來,再讓魚出去,以滿足答案最優

點選檢視程式碼
#include  <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e4+5;
const double eps=1e-9; 
int sum[N];
int n,a,cnt[N],jcnt[N];
struct Fs
{
	int x,w,v;
}f[N];
bool cmp(Fs a,Fs b)
{
	return a.x<b.x;
}
map <double,int> tmm;
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
//	freopen("EVA1.in","r",stdin);
	cin>>n>>a;
	for(int i=1;i<=n;i++)
	{
		cin>>f[i].w>>f[i].x>>f[i].v;	
	}	
	sort(f+1,f+1+n,cmp);ll ans=0;
	for(int i=1;i<=n;i++)
	{
		tmm.clear();
		ll res=f[i].w;
		for(int j=1;j<=n;j++)
		{
			if(i==j)continue;
			if(f[j].v==f[i].v)
			{
				if(f[j].x>=f[i].x&&f[j].x-f[i].x<=a)res+=f[j].w;
				// cout<<res<<endl;
				continue;
			}
			// if(f[j].x<f[i].x&&f[j].v<=f[i].v)continue;

			double l=1.0*(f[i].x-f[j].x)/(f[j].v-f[i].v);
			double r=1.0*(f[i].x-f[j].x+a)/(f[j].v-f[i].v);
			// cout<<t<<" "<<r<<rdl;
			// if(t<0)continue;
			
			if(l>r-eps)swap(l,r);//先要換位置,再判斷是否r<0
			if(r<0)continue;
			l=max(l,0.0000);
			tmm[l]+=f[j].w;
			tmm[r+eps]-=f[j].w;
			// if(f[j].x>f[i].x&&f[j].v>=f[i].v&&f[j].x-f[i].x>a)continue;
		}
		ans=max(ans,res);
		for(auto it:tmm)
		{
			res+=(it.second);
			ans=max(ans,res);
		}
	}
	cout<<ans;
	return 0;
}
/*
3 10
1 15 55
10 20 55
100 25 55
*/

T3

計數題
做法一:
排序\(a\)陣列,然後,我們初始左右指標\(l=1,r=n\),在滿足\(l<r企鵝a[l]+a[r]>=k\)的情況下不斷讓\(r\)指標右移,這樣,一定會有一個邊界,使得左端點\(a_l\)只能與\([r,n]\)\(a\)匹配,我們把他們加入到數列中,用\(ans\)乘上貢獻,類似插空的思想,當前未放入\(a_l,a_r\),
數列中已經包含\([1,l-1],[r+1,n]\),這樣就有\(n-r+l-1+1\)個空,再減去有\([1,l-1]\)元素周圍不能放\(a_r,a_l\)所以,貢獻為\(n-r+l-2\times (l-1)\),但是要注意最後還用相同數的情況,所以乘上相同數階乘的逆元即可

點選檢視程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define ull unsigned long long
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
//#define int long long
#define pb push_back

// #pragma comment(linker, ¡°/STACK:512000000,512000000¡±) 
using namespace std;
const int N = 2e5+5,mod=998244353,inf=1e9;
ll n,k,a[N],jie[N];
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}
ll calc(ll l,ll r)
{
	return (n-l-r+2);
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	jie[0]=1;
	for(ll i=1;i<=n;i++)jie[i]=jie[i-1]*i%mod;
	sort(a+1,a+1+n);
	ll l=1,r=n;
	ll ans=1;
	while(l<=r)
	{
		while(l<r&&a[r]+a[l]>=k)
		{	
			ans=ans*calc(l,r)%mod;
			r--;
		}
		ans=ans*calc(l,r)%mod;
		l++;
	}
	ll cnt=1;
	a[n+1]=inf;
	for(int i=2;i<=n+1;i++)
	{
		if(a[i]==a[i-1])cnt++;
		else
		{
			ans=ans*qpow(jie[cnt],mod-2)%mod;
			cnt=1;
		}
	}
	cout<<ans<<endl;
	// for()
	return 0;
}