2025“钉耙编程”中国大学生算法设计春季联赛(5)

小凯逛超市

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1000000007;
int f[405][405];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,m,v;
		cin>>n>>m>>v;
		memset(f,0,sizeof(f));
		f[0][0]=1;
		for(int t=1;t<=n;t++)
		{
			int g;
			cin>>g;
			for(int i=1;i<=m;i++)
			{
				for(int j=g;j<=v;j++)
				{
					(f[i][j]+=f[i-1][j-g])%=mod;
				}
			}
		}
		cout<<accumulate(f[m]+1,f[m]+v+1,0ll)%mod<<endl;
	}
	return 0;
}

小凯在长跑

  • hypot:给定两点横纵坐标差,计算距离。例如:hypot(x,y)
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int d,r,x,y;
		cin>>d>>r>>x>>y;
		double ans;
		if(abs(y)<=d)
		{
			ans=min(abs(x-r),abs(x+r));
		}
		else if(y>=d)
		{
			ans=abs(hypot(x,y-d)-r);
		}
		else if(y<=-d)
		{
			ans=abs(hypot(x,y+d)-r);
		}
		cout<<fixed<<setprecision(0)<<ans<<"\n";
	}
	return 0;
}

小凯做梦

  • 考虑在树上的任意一次移动都会让所有原来距离为1的点的距离变成 0,所有原来距离为 0 的点的距离变成 1
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
vector<pii>a[500005];
int d[500005],cnt;
void dfs(int u,int fa)
{
	cnt+=(d[u]>0);
	for(auto [v,w]:a[u])
	{
		if(v!=fa)
		{
			d[v]=(d[u]+w)%2;
			dfs(v,u);
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			a[i].clear();
		}
		for(int i=1;i<n;i++)
		{
			int u,v,w;
			cin>>u>>v>>w;
			w%=2;
			a[u].push_back({v,w});
			a[v].push_back({u,w});
		}
		d[1]=cnt=0;
		dfs(1,0);
		cout<<cnt*cnt*cnt+(n-cnt)*(n-cnt)*(n-cnt)<<"\n";
	}
	return 0;
}

小凯取石子

#include <bits/stdc++.h>
#define int long long
using namespace std;
const signed mod=998244353;
constexpr int power(int n,int p)
{
	if(p==0)
	{
		return 1;
	}
	long long tmp=power(n,p/2);
	if(p%2==1)
	{
		return tmp*tmp%mod*n%mod;
	}
	return tmp*tmp%mod;
}
constexpr signed inv2=power(2,mod-2);
int f(int x)
{
	if(x<0)
	{
		return 1;
	}
	if(x==0)
	{
		return 0;
	}
	if(x%5==2)
	{
		x/=5;
		x++;
		return 1-power(inv2,x)+mod;
	}
	else if(x%5==0)
	{
		x/=5;
		return 1-power(inv2,x)+mod;
	}
	else
	{
		return 1;
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		cout<<inv2*(f(n-1)+f(n-4))%mod<<endl;
	}
	return 0;
}

小凯爱数学

  • 可以用矩阵快速幂加速递推
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
typedef vector<vector<int> > matrix;
matrix operator *(matrix a,matrix b)
{
	int n=a.size(),m=a[0].size(),k=b[0].size();
	matrix res(n,vector<int>(k));
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<k;j++)
		{
			for(int l=0;l<m;l++)
			{
				(res[i][j]+=(a[i][l]*b[l][j]%mod))%=mod;
			}
		}
	}
	return res;
}
matrix E(int n)
{
	matrix res(n,vector<int>(n));
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			res[i][j]=0;
		}
		res[i][i]=1;
	}
	return res;
}
matrix power(matrix n,int p)
{
	if(p==0)
	{
		return E(n.size());
	}
	matrix tmp=power(n,p/2);
	if(p%2==1)
	{
		return tmp*tmp*n;
	}
	return tmp*tmp;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,m;
		cin>>n>>m;
		if(n<m)
		{
			vector<int>f(m);
			vector<int>g(m);
			f[0]=1;
			for(int i=1;i<=n;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j]+=g[(j-i%m+m)%m])%=mod;
				}
			}
			cout<<(f[0]-1+mod)%mod<<"\n";
		}
		else
		{
			matrix f(m,vector<int>(1));
			matrix g(m,vector<int>(1));
			f[0][0]=2;
			for(int i=1;i<m;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j][0]+=g[(j-i+m)%m][0])%=mod;
				}
			}
			vector<vector<int> >a(m,vector<int>(m));
			for(int i=0;i<m;i++)
			{
				for(int j=0;j<m;j++)
				{
					a[i][j]=f[(i-j+m)%m][0];
				}
			}
			f=power(a,n/m-1)*f;
			for(int i=1;i<=n%m;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j][0]+=g[(j-i+m)%m][0])%=mod;
				}
			}
			cout<<(f[0][0]-1+mod)%mod<<"\n";
		}
	}
	return 0;
}
  • 也可以用循环卷积加速单次合并
  • 可以使用resize函数改变vector的大小,自动补齐0
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef vector<int> poly;
const int mod=998244353;
int n,m;
poly E(int n)
{
	poly res(n);
	res[0]=1;
	return res;
}
int rev[5000005],p[5000005][2];
int power(int n,int p)
{
	if(p==0)
	{
		return 1;
	}
	long long tmp=power(n,p/2);
	if(p%2==1)
	{
		return tmp*tmp%mod*n%mod;
	}
	return tmp*tmp%mod;
}
void NTT(poly &f,int opt)
{
	int n=f.size();
	for(int i=1;i<n;i++)
	{
		if(i<rev[i])
		{
			swap(f[i],f[rev[i]]);
		}
	}
	for(int m=2;m<=n;m*=2)
	{
		int k=m/2;
		for(int i=0;i<n;i+=m)
		{
			long long cur=1,step;
			if(opt==1)
			{
				step=p[m][0];
			}
			else
			{
				step=p[m][1];
			}
			for(int j=0;j<k;j++)
			{
				long long tmp=cur*f[i+j+k]%mod;
				f[i+j+k]=(f[i+j]-tmp)%mod;
				f[i+j]=(f[i+j]+tmp)%mod;
				cur=cur*step%mod;
			}
		}
	}
}
poly operator*(poly a,poly b)
{
	poly c(a.size()+b.size()-1);
	int p=0;
	while((1<<p)<c.size())
	{
		p++;
	}
	for(int i=1;i<(1<<p);i++)
	{
		rev[i]=(rev[i>>1]>>1);
		if(i&1)
		{
			rev[i]+=(1<<(p-1));
		}
	}
	c.resize(1<<p);
	a.resize(c.size());
	b.resize(c.size());
	NTT(a,1),NTT(b,1);
	for(int i=0;i<c.size();i++)
	{
		c[i]=a[i]*b[i]%mod;
	}
	NTT(c,-1);
	p=power(c.size(),998244351);
	for(int i=0;i<c.size();i++)
	{
		c[i]=c[i]*p%mod;
	}
	for(int i=0;i+m<c.size();i++)
	{
		c[i]=(c[i]+c[i+m])%mod;
	}
	c.resize(m);
	return c;
}
void pre()
{
	for(int i=1;i<=22;i++)
	{
		p[1<<i][0]=power(3,998244352/(1<<i));
		p[1<<i][1]=power(3,998244352-998244352/(1<<i));
	}
}
poly power(poly n,int p)
{
	if(p==0)
	{
		return E(n.size());
	}
	poly tmp=power(n,p/2);
	if(p%2==1)
	{
		return tmp*tmp*n;
	}
	return tmp*tmp;
}
ostream& operator <<(ostream& os,poly x)
{
	for(int i:x)
	{
		os<<i;
		os<<' ';
	}
	return os;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	pre();
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		if(n<m)
		{
			poly f(m);
			poly g(m);
			f[0]=1;
			for(int i=1;i<=n;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j]+=g[(j-i%m+m)%m])%=mod;
				}
			}
			cout<<(f[0]-1+mod)%mod<<"\n";
		}
		else
		{
			poly f(m);
			poly g(m);
			f[0]=2;
			for(int i=1;i<m;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j]+=g[(j-i+m)%m])%=mod;
				}
			}
			f=f*power(f,n/m-1);
			for(int i=1;i<=n%m;i++)
			{
				g=f;
				for(int j=0;j<m;j++)
				{
					(f[j]+=g[(j-i+m)%m])%=mod;
				}
			}
			cout<<(f[0]-1+mod)%mod<<"\n";
		}
	}
	return 0;
}

小凯用git

  • 如果你要自定义构造函数,但在定义数组的时候又不想给出具体的值,那就要给构造函数的参数提供默认值
  • 大概是因为getline会把数字后的回车也读进去,所以要多循环一次
#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int>a[5005];
struct Branch
{
	string name;
	int node;
	bool life;
	Branch(string name="",int node=0)
	{
		this->name=name;
		this->node=node;
		this->life=true;
	}
}b[5005];
bool cmp(Branch a,Branch b)
{
	return a.name<b.name;
}
bool pd(int p,int q)
{
	if(p==q)
	{
		return true;
	}
	bool f=false;
	for(int fa:a[q])
	{
		f|=pd(p,fa);
	}
	return f;
}
int cntn,cntb,delb,head;
void output()
{
	cout<<cntb-delb<<"\n";
	for(int i=1;i<=cntb;i++)
	{
		if(b[i].life)
		{
			cout<<b[i].name<<" "<<b[i].node<<"\n";
		}
	}
	cout<<cntn<<"\n";
	for(int i=1;i<=cntn;i++)
	{
		cout<<a[i].size();
		sort(a[i].begin(),a[i].end());
		for(int fa:a[i])
		{
			cout<<" "<<fa;
		}
		cout<<"\n";
		a[i].clear();
	}
	fflush(stdout);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		head=cntb=cntn=1;
		delb=0;
		b[1]=Branch("main",1);
		int n;
		cin>>n;
		for(int t=0;t<=n;t++)
		{
			string s;
			getline(cin,s);
			if(s=="commit")
			{
				cntn++;
				a[cntn].push_back(b[head].node);
				b[head].node=cntn;
			}
			else if(s.substr(0,5)=="reset")
			{
				int p=0;
				for(int i=5;i<s.size();i++)
				{
					if(isdigit(s[i]))
					{
						p=p*10+s[i]-'0';
					}
				}
				if(p>0)
				{
					b[head].node=p;
				}
			}
			else if(s.substr(0,5)=="merge")
			{
				s.erase(0,6);
				int p=-1;
				for(int i=1;i<=cntb;i++)
				{
					if(b[i].name==s)
					{
						p=i;	
						break;
					}
				}
				if(!pd(b[p].node,b[head].node)&&!pd(b[head].node,b[p].node))
				{
					cntn++;
					a[cntn].push_back(b[p].node);
					a[cntn].push_back(b[head].node);
					b[head].node=cntn;
				}
				else if(pd(b[head].node,b[p].node))
				{
					b[head].node=b[p].node;
				}
			}
			else if(s.substr(0,6)=="branch")
			{
				s.erase(0,7);
				if(s[0]=='-')
				{
					s.erase(0,3);
					for(int i=1;i<=cntb;i++)
					{
						if(b[i].life&&b[i].name==s)
						{
							b[i].life=false;
							delb++;
							break;
						}
					}
				}
				else
				{
					int p=b[head].node;
					if(s.find(' ')!=-1)
					{
						for(int i=s.find(' ');i<s.size();i++)
						{
							if(isdigit(s[i]))
							{
								p=p*10+s[i]-'0';
							}
						}
					}
					string name="";
					for(int i=0;i<s.size()&&s[i]!=' ';i++)
					{
						name+=s[i];
					}
					bool f=false;
					for(int i=1;i<=cntb;i++)
					{
						if(b[i].life&&b[i].name==name)
						{
							f=true;
							break;
						}
					}
					if(f==false)
					{
						cntb++;
						b[cntb]=Branch(name,p);
					}
				}
			}
			else if(s.substr(0,8)=="checkout")
			{
				s.erase(0,9);
				for(int i=1;i<=cntb;i++)
				{
					if(b[i].life&&b[i].name==s)
					{
						head=i;
						break;
					}
				}
			}
		}
		sort(b+1,b+cntb+1,cmp);
		output();
	}
	return 0;
}

小凯想要MVP!

  • 考虑让两个子序列相交不影响长度和元素和相同,因此忽略掉这条限制,由此解除了两个子序列之间的纠缠
  • 然后观察到任意两个这样的子序列都可以等价为两个长度为\(\lfloor \frac{n}{2} \rfloor\)的序列,根据抽屉原理,只要\(\binom{n}{\lfloor \frac{n}{2} \rfloor}> m\cdot \lfloor \frac{n}{2} \rfloor\)就一定有解
  • 考虑到\(3^6=729\)\(3^{18}\)的时间复杂度差不多就接近程序的极限了
#include <bits/stdc++.h>
#define int long long
using namespace std;
int c[200005],s[1<<23];
unordered_map<int,bool>q;
int lowbit(int n)
{
	return n&(-n);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		int n,m;
		cin>>n>>m;
		bool f=false;
		for(int i=0;i<n;i++)
		{
			cin>>c[i];
		}
		if(n<24)
		{
			for(int m=1;m<=n;m++)
			{
				q.clear();
				for(int j=(1<<m)-1,t;j<(1<<n);t=j+lowbit(j),j=t|(((lowbit(t)/lowbit(j))>>1)-1))
				{
					int p=__builtin_ctz(j);
					s[j]=s[j-(1<<p)]+c[p];
					if(q.find(s[j])!=q.end())
					{
						f=true;
						break;
					}
					q[s[j]]=true;
				}
			}
		}
		else
		{
			f=true;
		}
		f==true?cout<<"YES\n":cout<<"NO\n";
	}
	return 0;
}
posted @ 2025-04-15 14:31  D06  阅读(65)  评论(0)    收藏  举报
//雪花飘落效果