新生賽及預選賽 10

Hanggoash發表於2024-10-06

新生賽及預選賽 10

這個和昨天的不太一樣,但只做了四道題,昨天有點小擺

A

還是很清晰的一個模擬題,預處理的時候判斷一下,在詢問的時候二分查詢就可以了。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
const int N=2e5+10;
int n,q,x[N],v[N],in[N];
inline void pre()
{
	re(n);
	for(register int i=1;i<=n;++i)
		re(x[i]),re(v[i]);
	in[1]=1;
	int nowv=0;x[n+1]=2005120700;
	for(register int i=1;i<=n;++i)
	{
		nowv+=v[i]; 
		if(x[i]+nowv<x[i+1])
		{
			v[i]=nowv;
			break;	
		}
		in[i+1]=1;
		nowv-=(x[i+1]-x[i]);
		v[i]=x[i+1]-x[i];
	}
}
inline void solve(int k)
{
	int pos=upper_bound(x+1,x+n+1,k)-x-1;
	if(in[pos]&&x[pos]+v[pos]>=k)puts("Yes");
	else puts("No");
}
int main()
{
	pre();
	int k;
	re(q);
	while(q--)
	{
		re(k);
		solve(k);
	}
	return 0;
}

B

\(k\) 個陣列 ,記從每個陣列的 \(a[i]\) 個人中共選出 \(x\) 個人的方案數為 \(f(x)\) (不能全都不選,也就是 \(x>0\) )。

\(\sum_{x=1}^{p} f(x)\)

B 題就是這個題在 \(k=2\) 時候的簡單版本,很明顯直接人肉列舉情況就可以透過了。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=13331;
int n,m,p;
int C[1010][1010];
inline void pre()
{
	cin>>n>>m>>p;
	for(int i=0;i<=1000;++i)	
	{
		C[i][0]=1;
		for(int j=1;j<=i;++j)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;				
	}
}
inline void solve()
{
	int ans=0;
	for(int i=0;i<=min(n,p);++i)
		for(int j=0;j<=m&&(i+j<=p);++j)
			ans+=1ll*C[n][i]*C[m][j]%MOD,ans%=MOD;
	cout<<ans-1;
}
signed main()
{
	pre();
	solve();
	return 0;
}

C

C 題就是 B 題的原版描述,個人寫了個 DP ,大概思路是:定義 \(dp[i][j]\) 為,前 \(i\) 個陣列,選了 \(j\) 個人的方案數。

那麼轉移方程其實也很明顯:

for(register int i=1;i<=n;++i)
{
    for(register int j=0;j<=p;++j)
    {
		for(register int x=0;x<=min(j,a[i]);++x)
        {
            dp[i][j]+=dp[i-1][j-x]*C(a[i],x);
		}
    }
}

但是可惜的是這道題的資料範圍十分的大, \(k\le \sum a_i\le10^6\) ,上述方法明顯具有正確性,但是無法透過該題目。

D

不會

E

給出若干個數字,已知這些數字是若干個未知數字的因數(可重),求出這若干個未知數字。

很明顯的是我們從最大的數開始列舉,然後剔除它所有的因數,直到集合裡再也沒有數字即可。

這裡用了個 multiset 實現,剔除操作是 wipe() 函式。

資料範圍很小,隨便怎麼做應該都能過。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x>9)wr(x/10);
	putchar(x%10^48);
 } 
multiset<int> s;
int n,a[100000];
int cnt,ans[100000];
inline void wipe(int x)
{
	int i;
	for(i=1;i*i<x;++i)
	{
		if(x%i!=0)continue;
		auto it=s.find(i);s.erase(it);
		it=s.find(x/i);s.erase(it);
	}
	if(i*i!=x)return;
	auto it=s.find(i);s.erase(it);
}
inline void pre()
{
	re(n);
	for(register int i=1;i<=n;++i)re(a[i]),s.insert(a[i]);
	while(s.size())
	{
		auto it=s.end();it--;
		ans[++cnt]=*it;
		wipe(*it);
	}
}
int main()
{
	pre();
	wr(cnt),putchar('\n');
	for(register int i=cnt;i>=1;--i)wr(ans[i]),putchar(' ');
	return 0;
 } 
 /*
12
1 2 1 6 3 5 1 2 3 4 6 12
 */

相關文章