2025杭电春季联赛(2)个人比赛记录

1002-学历史导致的

字符串模拟,数据量很小所以可以直接打表,开个map一一对应就好了

弱智错误1:当时脑子一抽直接分离天干地支再算数,写了半天。。。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<ll,ll>
#define db double
#define endl '\n'
#define llu long long unsigned int


string a[10]={"jia", "yi", "bing", "ding", "wu", "ji", "geng", "xin", "ren", "gui"};
string b[12]={"zi", "chou", "yin", "mao", "chen", "si", "wu", "wei", "shen", "you", "xu", "hai"};

void solve()
{
	
		ll ans=0;
		ll x=0,y=0,pos=0;
		string t;
		cin>>t;
		string s;
		for(ll j=t.length()-1;j>=0;j--)
		{
			string tmp=s;
			s.clear();
			s+=t[j];
			s+=tmp;
			for(ll k=0;k<12;k++)
			{
				if(s==b[k])
				{
					y=k;
					s.clear();
					pos=j;
					goto kk;
				}
			}
		}
		kk:;
		for(ll j=pos-1;j>=0;j--)
		{
			string tmp=s;
			s.clear();
			s+=t[j];
			s+=tmp;
		}
		for(ll j=0;j<10;j++)
		{
			if(a[j]==s)
			{
				x=j;
				break;
			}
		}
		ans+=x;
		if(x<y)x+=12;
		ll cnt=x-y;
		ans+=10*(cnt/2);
		cout<<ans+1984<<endl;	
	
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	ll tt=1;
	
	cin>>tt;
	
	while(tt--)
	solve();
	return 0;
}

1004-学DP导致的

由于读入字符串只包含小写字母,故最长上升子序列最长不会超过26,k若大于26则直接处理成26,然后拼接字符串无脑dp即可。

弱智错误2:k范围到了1e100还不用string存,直接白吃一发罚时。。。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<ll,ll>
#define db double
#define endl '\n'
#define llu long long unsigned int
const ll nn=2e5+5;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const ll INF=1e18;


string t;
string n;
void solve()
{
	cin>>t>>n;
	ll k=0;
	if(n.length()>2)k=26;
	else{
		for(ll i=0;i<n.length();i++)
		{
			k*=10;
			k+=n[i]-'0';
		}
	}
	string s;
	for(ll i=1;i<=min(k,26ll);i++)
	{
		s+=t;
	}
	ll ans=0;
	vector<ll>dp(s.length()+1);
	for(ll i=0;i<s.length();i++)
	{
		dp[i]=1;
		for(ll j=0;j<i;j++)
		{
			if(s[j]<s[i])dp[i]=max(dp[i],dp[j]+1);
		}
	}
	for(ll i=0;i<s.length();i++)ans=max(ans,dp[i]);
	cout<<ans<<endl;
	
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	ll tt=1;
	
	cin>>tt;
	
	while(tt--)
	solve();
	return 0;
}

1003-学数数导致的

枚举计数,但看过数据量发现必然不能真去暴力枚举,故思考优化方法:

注意到读入数组中元素不超过1e6,故可开数组a记录每个数最早出现的下标,找到目标序列的第一个p

再看需要构成的序列p,0,p,q,发现需要维护0的出现情况,故开数组b记录距当前位置最近的前导0的下标,这样遍历到第i个元素v[i]时,若a[v[i]]<b[i],则完成p,0,p的构造

而(p,q)对的数量显然由此状态下q的数量决定,故开数组c记录下标i之后存在多少不同的正整数

这样,遍历到v[i]时,若a[v[i]]<b[i],则令ans+=c[i]即可

这样就结束了。。。吗?

并没有,由于遍历到不同位置时可能遇相同的p或q,故需考虑去重:

每更新一次ans,把a[v[i]]的值设置为INF,这样下次遇相同的p时,自然不会重复地被识别为合法结果,又因遍历是正序的,故最初遇到的p所涵盖的q必然多于之后遇到的相同p,并不会算少

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define llu long long unsigned int
#define db double
#define endl '\n'
#define PII pair<ll,ll>
const ll inf=0x3f3f3f3f;
const ll mod=1e9+7;
const ll nn=1e6+5;
const ll mm=3005;
const ll INF=1e18;



ll mp[nn];
void solve()
{
	memset(mp,-1,sizeof mp);
	ll n;cin>>n;
	vector<ll>v(n);
	vector<ll>a(n),b(n);
	ll now=-1;
	for(ll i=0;i<n;i++)
	{
		cin>>v[i];
		if(v[i]==0)now=i;
		if(mp[v[i]]==-1&&v[i])mp[v[i]]=i;
		a[i]=now;
	}
	mp[0]=INF;
	set<ll>s;
	for(ll i=n-1;i>=0;i--)
	{
		b[i]=s.size();
		if(v[i])s.insert(v[i]);
	}
	ll ans=0;
	for(ll i=0;i<n;i++)
	{
		if(mp[v[i]]<a[i])ans+=b[i],mp[v[i]]=INF;
	}
	cout<<ans<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	ll tt=1;
	
	cin>>tt;
	
	while(tt--)
	solve();
    return 0;
}

1005-学几何导致的

已知相邻两直线间夹角为180/k,若要构成互相垂直的直线,则90/(180/k)必然是整数,即k%2==0

所以k为奇数时直接输出0

设首条直线为x

k为2时,有n/2条垂直于x的直线,n为偶则有n/2条平行,否则有n/2+1条

k>2时,将所有直线按n%(k/2)分组,则有n%(k/2)组直线共有n/k+1条,有k/2-n%(k/2)组直线共有n/k条,每组直线本身都是k=2的情况,直接套用k=2时的计算方法即可

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define llu long long unsigned int
#define db double
#define endl '\n'
#define PII pair<ll,ll>
const ll inf=0x3f3f3f3f;
const ll mod=1e9+7;
const ll nn=2e5+5;
const ll mm=3005;
const ll INF=1e18;


ll fuck(ll x)
{
	return (x/2)*((x+1)/2);
}
void solve()
{
	ll n,k;cin>>n>>k;
	if(k&1)cout<<0<<endl;
	else{
		ll x=k/2;
		cout<<n%x*fuck(n/x+1)+(x-n%x)*fuck(n/x)<<endl;;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	ll tt=1;
	
	cin>>tt;
	
	while(tt--)
	solve();
    return 0;
}

1006-学博弈论导致的

这题乍一看很混乱,有如此多种选择,但仔细观察后可以发现,若给红蓝宝石以及宝盒各赋一个合适的价值,即可将混乱的本题转化成极其直白的巴什博弈模型:

1.根据第一条,暂定红宝石的价值为1,一次可拿走的最大价值为3

2.把蓝宝石变成红宝石的过程需要消耗总价值,故二者价值必不能相等

3.确定蓝宝石价值为2(若大于2,则“一红一蓝”的取法消耗价值超过了3)

7.确定宝盒价值为4

用各条件检验,三者价值均合法,故此问题转化为总价值为r+b2+m4,一次拿取价值不超过3的巴什博弈

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define llu long long unsigned int
#define db double
#define endl '\n'
#define PII pair<ll,ll>
const ll inf=0x3f3f3f3f;
const ll mod=1e9+7;
const ll nn=2e5+5;
const ll mm=3005;
const ll INF=1e18;



void solve()
{
	ll r,b,m;
	cin>>r>>b>>m;
	ll cnt=0;
	cnt+=r+b*2+m*4;
	if(cnt%4)cout<<"Alice"<<endl;
	else cout<<"Bob"<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	ll tt=1;
	
	cin>>tt;
	
	while(tt--)
	solve();
    return 0;
}
posted @ 2025-03-15 16:43  Linxuan_MY  阅读(79)  评论(0)    收藏  举报