20240814

赛时得分

题目 A B C D 总分 排名 比例
满分 100 100 100 100 400 160 100%
得分 50 30 0 20 100 93 58.1%

A. 二进制的数字(50/100)

\(\text{50%}\) 得分做法,十进制转二进制后直接从 \(1\) 开始枚举,如果满足 \(k\)\(1\),我们就 ans++,直到 ans=n 结束。

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
ll n,k,cnt,ans;
string now;
string change(ll n)
{
	if(n==0) return "0";
	string ans;
	while(n!=1)
	{
		ans+=to_string(n%2);
		n/=2;
	}
	ans+="1";
	reverse(ans.begin(),ans.end());
	return ans;
}
int main()
{
	freopen("num.in","r",stdin);
	freopen("num.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k;
	for(int i=1;;i++)
	{
		cnt=0;
		now=change(i);
		for(int j=0;j<now.length();j++)
		{
			if(now[j]=='1') cnt++;
		}
		if(cnt!=k) continue;
		else ans++;
		if(ans==n)
		{
			cout<<now;
			return 0;
		}
	}
	return 0;
}

B. 插入加号(30/100)

\(\text{30%}\) 得分做法,考虑 dfs,我们插入加号的位置一定在两个数之间,就搜索加号放的位置,扔到一个 set 中维护,当元素个数 \(=k\) 时,我们就需要求一下和即可。

还好昨晚鬼使神差看了 Luogu P1036 选数 这个题,跟 B 题的 dfs 思路是很像的。

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int mod=1e9+7;
ll n,k,ans;
string tar;
set<ll> pl;
ll getnum(string s)
{
	ll ans=0,res=0;
	for(int i=0;i<s.length();i++)
	{
		if(s[i]=='+')
		{
			ans+=res%mod;
			res=0;
		}
		else
		{
			res*=10;
			string now="";
			now+=s[i];
			res+=stoi(now);
			res%=mod;
		}
	}
	ans+=res%mod;
	return ans;
}
string makestr(set<ll> pl,string s)
{
	string ans="";
	ans+=s[0];
	for(int i=1;i<n;i++)
	{
		if(pl.find(i)!=pl.end()) ans+="+",ans+=s[i];
		else ans+=s[i];
	}
	return ans;
}
void dfs(ll now)
{
	if(now>n) return;
	if(now==n)
	{
		if(pl.size()==k)
		{
			ans+=getnum(makestr(pl,tar));
			ans%=mod;
		}
	}
	pl.insert(now);
	dfs(now+1);
	pl.erase(pl.find(now));
	dfs(now+1);
	return;
}
int main()
{
	freopen("plus.in","r",stdin);
	freopen("plus.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k>>tar;
	dfs(1);
	cout<<ans;
	return 0;
}

C. 疯狂的动态树(40/100)

\(\text{20%}\) 得分做法,考虑暴力,我们写三个 dfs,分别用于换根、路径查询、子树查询。

  • 对于换根 dfs,我们在这里统计 \(d,fat\) 数组,分别记录的是深度和父节点。
  • 对于路径查询 dfs,我们直接 dfs 到终点,传参记录答案即可。
  • 对于子树查询 dfs,由于树上 dfs 不会走重复的路,我们每到一个点直接记录答案即可。记得我们搜索的是子树,子树根节点 \(x\) 父亲不是 \(0\),而是 \(fat_x\)
#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=3e5+1;
vector<ll> e[N];
ll id,n,m,op,u,v,d[N],fat[N],ans;
void dfs1(ll x,ll fa)
{
	d[x]=d[fa]+1;
	fat[x]=fa;
	for(auto y:e[x])
	{
		if(y!=fa) dfs1(y,x);
	}
	return;
}
void dfs2(ll x,ll fa,ll now)
{
	if(x==v) ans=now;
	for(auto y:e[x])
	{
		if(y!=fa) dfs2(y,x,now+(d[y]-1));
	}
	return;
}
void dfs3(ll x,ll fa)
{
    ans+=(d[x]-1);
	for(auto y:e[x])
	{
		if(y!=fa) dfs3(y,x);
	}
	return;
}
int main()
{
	freopen("crazy.in","r",stdin);
	freopen("crazy.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>id>>n>>m;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs1(1,0);
	while(m--)
	{
		cin>>op;
		if(op==0)
		{
			cin>>u;
			memset(d,0,sizeof(d));
			memset(fat,0,sizeof(fat));
			dfs1(u,0);
		}
		else if(op==1)
		{
			cin>>u>>v;
			ans=0;
			dfs2(u,0,d[u]-1);
			cout<<ans<<endl;
		}
		else
		{
			cin>>u;
			ans=0;
			dfs3(u,fat[u]);
			cout<<ans<<endl;
		}
	}
	return 0;
}

\(\text{40%}\) 得分做法,这个做法是没有换根操作的部分分。

对于路径查询操作,不难发现深度上答案即为 \(u\) 到根节点的深度总和 + \(v\) 到根节点的深度总和 - \(lca(u,v)\) 到根节点的深度总和。化简就是 \(\sum^{d_u}_{i=d_{lca(u,v)}} + \sum^{d_v}_{i=d_{lca(u,v)}}-\ d_{lca(u,v)}\) 我们只需要等差数列维护一下即可。

对于子树查询操作,我们提前 dfs 预处理一下以每个节点为根节点的子树深度和是多少即可,思想类似于前缀和。

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=3e5+1;
vector<ll> e[N];
ll id,n,m,op,u,v,d[N],fat[N],ans,dep[N],p[N][21],sum[N];
void dfs(ll x,ll fa)
{
	d[x]=d[fa]+1;
	p[x][0]=fa;
	fat[x]=fa;
	sum[x]=d[x]-1;
	for(int i=1;(1<<i)<=d[x];i++) p[x][i]=p[p[x][i-1]][i-1];
    for(auto y:e[x])
    {
        if(y!=fa)
        {
            dfs(y,x);
            sum[x]+=sum[y];
        }
    }
	return;
}
ll lca(ll a,ll b)
{
	if(d[a]>d[b]) swap(a,b);
	for(int i=20;i>=0;i--)
	{
		if(d[a]<=d[b]-(1<<i)) b=p[b][i];
	}
	if(a==b) return a;
	for(int i=20;i>=0;i--)
	{
		if(p[a][i]==p[b][i]) continue;
		else a=p[a][i],b=p[b][i];
	}
	return p[a][0];
}
int main()
{
	freopen("crazy.in","r",stdin);
	freopen("crazy.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>id>>n>>m;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
    while(m--)
    {
        cin>>op>>u;
        if(op==0)
        {
            memset(d,0,sizeof(d));
            memset(p,0,sizeof(p));
            memset(fat,0,sizeof(fat));
            memset(sum,0,sizeof(sum));
            dfs(u,0);
        }
        else if(op==1)
        {
            cin>>v;
            ll st=d[lca(u,v)]-1,ed1=d[u]-1,ed2=d[v]-1;
            ans=0;
            ans+=(st+ed1)*(ed1-st+1)>>1;
            ans+=(st+ed2)*(ed2-st+1)>>1;
            ans-=st;
            cout<<ans<<endl;
        }
        else cout<<sum[u]<<endl;
    }
	return 0;
}

D. 聪明格(20/100)

\(\text{20%}\) 得分做法,看到 \(n=3\) 的部分分,直接打表。一共有 \(12\) 种数独方案,我们需要统计一下乘积数组中各元素对应坐标,然后拿到我们的 \(12\) 个方案中一一比较,满足方案的我们就方案数 ++,把字典序最小那个编号存下来,最后输出即可。

但这样策略显然有反例。例如我出一个乘积数组如下:

6 6 3
6 2 6
1 6 6

由于此数组非联通,而我统计出来的结果是有 \(6\)\(6\),所以我需要特判一下这种情况,还有把它瞬时针旋转 \(90\) 度(放到另两个对角)的情况即可。

可能还有反例吧。但是我懒得找了。而且出题人也没有造特殊数据卡这种做法,所以就水来 \(\text{20pts}\)

#include<bits/stdc++.h>
#define Std_Maker lhm
#define ll long long
using namespace std;
const int N=21;
ll n,mul[N][N];
struct lhm
{
	ll a[N][N];
}s[N];
void pre()
{
	s[1].a[1][1]=1;s[1].a[1][2]=2;s[1].a[1][3]=3;
	s[1].a[2][1]=2;s[1].a[2][2]=3;s[1].a[2][3]=1;
	s[1].a[3][1]=3;s[1].a[3][2]=1;s[1].a[3][3]=2;
	s[2].a[1][1]=1;s[2].a[1][2]=2;s[2].a[1][3]=3;
	s[2].a[2][1]=3;s[2].a[2][2]=1;s[2].a[2][3]=2;
	s[2].a[3][1]=2;s[2].a[3][2]=3;s[2].a[3][3]=1;
	s[3].a[1][1]=1;s[3].a[1][2]=3;s[3].a[1][3]=2;
	s[3].a[2][1]=2;s[3].a[2][2]=1;s[3].a[2][3]=3;
	s[3].a[3][1]=3;s[3].a[3][2]=2;s[3].a[3][3]=1;
	s[4].a[1][1]=1;s[4].a[1][2]=3;s[4].a[1][3]=2;
	s[4].a[2][1]=3;s[4].a[2][2]=2;s[4].a[2][3]=1;
	s[4].a[3][1]=2;s[4].a[3][2]=1;s[4].a[3][3]=3;
	s[5].a[1][1]=2;s[5].a[1][2]=1;s[5].a[1][3]=3;
	s[5].a[2][1]=1;s[5].a[2][2]=3;s[5].a[2][3]=2;
	s[5].a[3][1]=3;s[5].a[3][2]=2;s[5].a[3][3]=1;
	s[6].a[1][1]=2;s[6].a[1][2]=1;s[6].a[1][3]=3;
	s[6].a[2][1]=3;s[6].a[2][2]=2;s[6].a[2][3]=1;
	s[6].a[3][1]=1;s[6].a[3][2]=3;s[6].a[3][3]=2;
	s[7].a[1][1]=2;s[7].a[1][2]=3;s[7].a[1][3]=1;
	s[7].a[2][1]=1;s[7].a[2][2]=2;s[7].a[2][3]=3;
	s[7].a[3][1]=3;s[7].a[3][2]=1;s[7].a[3][3]=2;
	s[8].a[1][1]=2;s[8].a[1][2]=3;s[8].a[1][3]=1;
	s[8].a[2][1]=3;s[8].a[2][2]=1;s[8].a[2][3]=2;
	s[8].a[3][1]=1;s[8].a[3][2]=2;s[8].a[3][3]=3;
	s[9].a[1][1]=3;s[9].a[1][2]=1;s[9].a[1][3]=2;
	s[9].a[2][1]=1;s[9].a[2][2]=2;s[9].a[2][3]=3;
	s[9].a[3][1]=2;s[9].a[3][2]=3;s[9].a[3][3]=1;
	s[10].a[1][1]=3;s[10].a[1][2]=1;s[10].a[1][3]=2;
	s[10].a[2][1]=2;s[10].a[2][2]=3;s[10].a[2][3]=1;
	s[10].a[3][1]=1;s[10].a[3][2]=2;s[10].a[3][3]=3;
	s[11].a[1][1]=3;s[11].a[1][2]=2;s[11].a[1][3]=1;
	s[11].a[2][1]=1;s[11].a[2][2]=3;s[11].a[2][3]=2;
	s[11].a[3][1]=2;s[11].a[3][2]=1;s[11].a[3][3]=3;
	s[12].a[1][1]=3;s[12].a[1][2]=2;s[12].a[1][3]=1;
	s[12].a[2][1]=2;s[12].a[2][2]=1;s[12].a[2][3]=3;
	s[12].a[3][1]=1;s[12].a[3][2]=3;s[12].a[3][3]=2;
	return;
}
bool pd(int k,set<ll> p[])
{
	for(int i=1;i<=250;i++)
	{
		if(p[i].size()==0) continue;
		else
		{
			if(i==6 and p[i].size()==6)
			{
				ll cnt1=1,cnt2=1;
				bool vis3=0,vis1=0;
				for(auto j:p[i])
				{
					if(j==1)
					{
						vis1=1;
						break;
					}
					if(j==3)
					{
						vis3=1;
						break;
					}
				}
				if(vis1==1)
				{
					cnt1*=s[k].a[1][1];
					cnt1*=s[k].a[1][2];
					cnt1*=s[k].a[2][1];
					cnt2*=s[k].a[2][3];
					cnt2*=s[k].a[3][2];
					cnt2*=s[k].a[3][3];
					if(cnt1!=6 or cnt2!=6) return 0;
				}
				if(vis3==1)
				{
					cnt1*=s[k].a[1][3];
					cnt1*=s[k].a[1][2];
					cnt1*=s[k].a[2][3];
					cnt2*=s[k].a[2][1];
					cnt2*=s[k].a[3][2];
					cnt2*=s[k].a[3][1];
					if(cnt1!=6 or cnt2!=6) return 0;
				}
			}
			else
			{
				ll cnt=1;
				for(auto j:p[i])
				{
					if(j==3 or j==6 or j==9) cnt*=s[k].a[j/n][3];
					else cnt*=s[k].a[j/n+1][j%n];
				}
				if(cnt!=i) return 0;
			}
		}
	}
	return 1;
}
void sub()
{
	pre();
	ll ans=0,pos=0;
	set<ll> p[301];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>mul[i][j];
			p[mul[i][j]].insert(n*(i-1)+j);
		}
	}
	for(int k=1;k<=12;k++)
	{
		if(pd(k,p)==1)
		{
			ans++;
			if(ans==1) pos=k;
		}
	}
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++) cout<<s[pos].a[i][j]<<" ";
		cout<<endl;
	}
	return;
}
int main()
{
	freopen("smart.in","r",stdin);
	freopen("smart.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	if(n==3)
	{
		sub();
		return 0;
	}
	return 0;
}
posted @ 2024-08-14 14:20  Lithium_Chestnut  阅读(7)  评论(0)    收藏  举报