2025 --【J+S 二十连测】-- 第一套 总结

总结

T1

考场上很快写出了正解,没有问题

T2

考场上很快写出了正解,但提交时交了两边,故0分

T3

考场上很快写出了正解,没有问题

T4

考场上很快写出了部分分,拿满了,没有问题

题解

T1

照题意模拟即可

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
string f(string s,int x)
{
	int n=s.size()-1;
	int d=(s[x]>='5');
	for(int i=x;i<=n;i++) s[i]='0';
	for(int i=x-1;i>1;i--)
	{
		int ns=s[i]-'0'+d;
		if(ns<=9) d=0,s[i]=ns+'0';
		else d=1,s[i]=ns-10+'0';
	}
	if(d==1&&s[1]=='9') s.insert(1,"1"),s[2]='0';
	else if(d==1) s[1]=s[1]+1;
	return s;
}
signed main()
{
	freopen("Number.in","r",stdin);
	freopen("Number.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		int n;cin>>n;
		string s;cin>>s;
		cout<<s;
		s=' '+s;
		int fds=1;
		for(int i=n;i>fds;i--)
		{
			s=f(s,i);
			if(s.size()>n+1&&fds==1) fds=2,i++;
			cout<<" ->"<<s;
		}
		cout<<endl;
	}
	return 0;
}

T2

因为是纵切,所以看其对称区域是否有即可

多测不清空,亲人两行泪

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
map<pair<int,int>,int> mp;
signed main()
{
	freopen("Color.in","r",stdin);
	freopen("Color.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		mp.clear();
		int n,m,k;cin>>k>>n>>m;
		for(int i=1;i<=k;i++)
		{
			int tmp;cin>>tmp;
			int x=(tmp+m-1)/m,y=tmp-m*(x-1);
			mp[{x,y}]=1;
		}
		int f=1;
		for(auto x:mp)
		{
			pair<int,int> y=x.first;
			y.second=m-y.second+1;
			if(mp.find(y)==mp.end())
			{
				f=0;
				break;
			}
		}
		if(f) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	return 0;
}

T3

如果将题目弱化成模板LIS,大家一定会做

其实对于本题是一个道理,只是更新时要新开一个临时数组即可

要用二分法,因为总量为 \(10^6\) 的量级

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=5e3+5;
int dp[maxn],a[maxn][maxn],now[maxn];
signed main()
{
	freopen("yet.in","r",stdin);
	freopen("yet.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,m,ans=0;cin>>m>>n;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
	for(int i=1;i<=n;i++) dp[i]=-1;
	for(int i=1;i<=n;i++)
	{
		int f=0;
		for(int j=1;j<=n;j++) now[j]=inf;
		for(int j=1;j<=m;j++)
		{
			if(dp[ans]<a[i][j]) f=1,dp[ans+1]=now[ans+1]=min(now[ans+1],a[i][j]);
			else
			{
				int p=lower_bound(dp+1,dp+1+ans,a[i][j])-dp;
				now[p]=min(now[p],a[i][j]);
			}
		}
		if(f) ans++;
		for(int j=1;j<=ans;j++) dp[j]=min(dp[j],now[j]);
	}
	cout<<ans;
	return 0;
}

T4

由于是第 \(k\) 大,而求第 \(k\) 大其实只有两种:

  • 枚举
  • 二分

显然这道题是二分,因为 \(k\) 太大了

那么对于二分答案,必然二分“答案”(v),即求有多少个数对 \((i,j),1\le i\le j\le n\),满足 \(\frac{x_i\times y_i+x_j\times y_j}{x_i+ x_j}\ge v\)

那么将原式变一下,即:

\[\frac{x_i\times y_i+x_j\times y_j}{x_i+ x_j}\ge \frac{v}{1} \]

利用交叉相乘得

\[x_i\times y_i+x_j\times y_j\ge (x_i+ x_j)\times v \]

利用乘法分配律得:

\[x_i\times y_i+x_j\times y_j\ge x_i\times v+x_j\times v \]

再移个项:

\[x_i\times y_i-x_i\times v\ge x_j\times v-x_j\times y_j \]

那么直接对比即可

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
#define exp 1e-3
using namespace std;
const int maxn=2e5+5;
int a[maxn],c[maxn],n,k;
double p[maxn],q[maxn];
bool check(double t)
{
    int j=0,ans=0;
    for(int i=1;i<=n;i++)
    {
        double x=a[i]*1.0*c[i],y=t*a[i]; 
        p[i]=x-y;
        q[i]=y-x; 
        if(q[i]-p[i]<exp) ans--;
    }
    sort(p+1,p+n+1);
    sort(q+1,q+n+1);
    for(int i=1;i<=n;i++)
    {
        while((q[j+1]-p[i])<exp&&j+1<=n) j++;
        ans+=j;
    }
    return (ans/2<k);
}
signed main()
{
	freopen("Function.in","r",stdin);
	freopen("Function.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i]>>c[i];
	double l=0,r=1e18,mid;
    while((r-l)>exp)
    {
        double mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
	printf("%.3lf",l);
	return 0;
}

T5

有一个道理:断开一个点和去掉以这个点为根的子树是差不多的

有一个发现:\(0\le a_i\le 2\)!

有一个观察:如果去掉一个叶子,那么原树不会断开

有一个公理:如果有一棵大小大于2的数,叶子节点移动大于2

合起来就会发现:我每次通过若干去掉叶子移动能使原树的权值和减0或2

那么我直接判奇偶性,若当前子树大于k且奇偶性相同,则答案加一并断开即可

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e6+5;
vector<int> g[maxn];
int dp[maxn][2],ans,n,k,a[maxn];
void dfs(int x,int fa)
{
	dp[x][0]=-inf;
	dp[x][1]=-inf;
	dp[x][a[x]%2]=a[x];
	for(auto to:g[x])
	{
		if(fa==to) continue;
		dfs(to,x);
		int s[2]={};
		s[0]=max(dp[x][0]+dp[to][0],dp[x][1]+dp[to][1]);
		s[1]=max(dp[x][1]+dp[to][0],dp[to][1]+dp[x][0]);
		dp[x][0]=s[0],dp[x][1]=s[1];
	}
	if(dp[x][k%2]>=k)
	{
		ans++;
		dp[x][0]=0;
		dp[x][1]=-inf;
	}
	dp[x][0]=max(dp[x][0],0ll);
}
signed main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		cin>>n>>k;
		for(int i=1;i<=n;i++) cin>>a[i],g[i].clear();
		for(int i=1;i<n;i++)
		{
			int u,v;cin>>u>>v;
			g[u].push_back(v);
			g[v].push_back(u);
		}
		ans=0;
		dfs(1,-1);
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2025-10-03 10:00  Engle_Chen  阅读(21)  评论(0)    收藏  举报