2025 SMU WINTER 3th
前言
内含牛客训5,6,vj round 10补题
牛客训5
L 构造恰有两队数互质的三元组

看题目的时候注意到是数据是1e6,暴力的去枚举的话肯定会t的。但我还是写了遍三次循环的,想着后续用什么来优化一下。后面发现不行,回归到了最开始的思路,三个一组,按偶奇偶排列,但是也不行,偶奇偶之后就是奇偶奇。。。
看题解说是:六个一组,
(x+2,x+5都是3的倍数,豪强哇〒▽〒)
下面这个是我补题的时候不断wa不断修改的代码,有点丑。
点击查看代码
void solve() {
ll n;cin>>n;
ll ans=n/3;
vector<ll>a;
// cout<<ans<<'\n';
if(n<=3)
{
cout<<0<<'\n';
return;
}else{
cout<<ans<<'\n';
}
if((n%6)<=2)
{
for(ll i=1;i<=n;i+=6)
{
a.push_back(i);
if(i+1<=n) a.push_back(i+1);
// else break;
if(i+3<=n) a.push_back(i+3);
// else break;
if(i+2<=n) a.push_back(i+2);
// else break;
if(i+4<=n) a.push_back(i+4);
// else break;
if(i+5<=n) a.push_back(i+5);
// else break;
}
ll cnt=1;
for(ll i=0;i<(ll)a.size();i+=3)
{
if(cnt<=ans)
{
cout<<a[i]<<" "<<a[i+1]<<" "<<a[i+2]<<'\n';
cnt++;
}else{
break;
}
}
}else{
if(n>=4&&n<6)
{
cout<<"1 2 4\n";
}else if(n>=6&&n<9)
{
cout<<"1 2 4\n3 5 9\n";
}else
cout<<"1 2 4\n3 5 9\n7 8 6\n";
ll cnt=3;
for(ll i=10;i<=n;i+=6)
{
a.push_back(i);
if(i+1<=n) a.push_back(i+1);
// else break;
if(i+4<=n) a.push_back(i+4);
// else break;
if(i+2<=n) a.push_back(i+2);
// else break;
if(i+3<=n) a.push_back(i+3);
// else break;
if(i+5<=n) a.push_back(i+5);
// else break;
}
for(ll i=0;i<(ll)a.size();i+=3)
{
if(cnt<ans)
{
cout<<a[i]<<" "<<a[i+1]<<" "<<a[i+2]<<'\n';
cnt++;
}else{
break;
}
}
}
}
好看版
void solve() {
int n;
cin>>n;
if (n<=3) {
cout<<0<<endl;
}
else if (n<=5) {
cout<<"1"<<endl;
cout<<"2 3 4"<<endl;
}
else {
cout<<n/3<<endl;
int c=1;
if (n%6<3) {
for (;c<=n/3*3;) {
cout<<c<<" "<<c+1<<" "<<c+3<<endl;
cout<<c+2<<" "<<c+4<<" "<<c+5<<endl;
c+=6;
}
}
else {
cout<<"1 2 4\n3 5 9\n7 8 6\n";
c=10;
for (;c<=n/3*3;) {
cout<<c<<" "<<c+1<<" "<<c+4<<endl;
cout<<c+2<<" "<<c+3<<" "<<c+5<<endl;
c+=6;
}
}
}
}
E 小L的井字棋

样例1,答案为yes yes
2
OGX
XOO
GGX
GGG
GGG
GXO
样例2,答案为no
1
OXX
XOO
GGG
思路:分类讨论题。如果双方都没下或者下的次数小于2,那么直接输出yes;
否则,如果已给出的盘上有存在X的行或列或对角线有两空或一空(没O),则ok
点击查看代码
char mp[5][5];
bool check(ll x,ll y)
{
bool ok=true;
for(ll i=1;i<=3;++i)
{
if(mp[i][y]=='O')
{
ok=false;
break;
}
}
if(ok){
return true;
}
ok=true;
for(ll i=1;i<=3;++i)
{
if(mp[x][i]=='O')
{
ok=false;
break;
}
}
if(ok) return true;
// ok=true;
if(x==y)
{
ok=true;
for(ll i=1;i<=3;++i)
{
if(mp[i][i]=='O')
{
ok=false;
break;
}
}
if(ok) return true;
}
if(x+y==4) //反斜对角线表示
{
ok=true;
for(ll i=1;i<=3;++i)
{
if(mp[i][4-i]=='O')
{
ok=false;
break;
}
}
if(ok) return true;
}
return false;
}
void solve()
{
ll cnt=0;
for(ll i=1;i<=3;++i)
{
for(ll j=1;j<=3;++j)
{
cin>>mp[i][j];
if(mp[i][j]=='X')
{
cnt++;
}
}
}
if(cnt>2)
{
for(ll i=1;i<=3;++i)
{
for(ll j=1;j<=3;++j)
{
if(mp[i][j]=='X'&&check(i,j))
{
cout<<"Yes\n";
return;
}
}
}
cout<<"No\n";
}else{
cout<<"Yes\n";
return;
}
cout<<"No\n";
}
I 小L的数学题

猜测大法
以后也可以多猜猜呢,别总是想着合理证明
点击查看代码
void solve()
{
ll n,m;cin>>n>>m;
if(n==0)
{
if(m==0)
{
cout<<"Yes\n";
return;
}else{
cout<<"No\n";
}
}else{
if(m==0)
{
cout<<"No\n";
}else{
cout<<"Yes\n";
}
}
}
牛客训6
A
反思:作为一个签到题,我的反应速度实在是有点慢了
我回想了下当时的状态
导致速度慢的原因有下
- 读题不认真,老毛病跳着读题。而且看着字多的“头晕”
- 思路浮现不清晰(感觉归根到底还是读题不认真的原因)
B好伙计猜拳
动态规划
前置知识是 用动态规划写最大上升子序列
点击查看代码
ll a[1010],b[1010],n,c1,c2,dp[1010][2];
void solve() {
cin>>n>>c1>>c2;
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
ll ans=1e18;
for(ll i=1;i<=n;++i)
{
cin>>a[i]>>b[i];
}
for(ll i=1;i<=n;++i)
{
for(ll j=0;j<=i-1;++j)
{
if(a[j]<=a[i]&&b[j]<=b[i])
//(aj,bj)后接(ai,bi)
{
dp[i][0]=min(dp[i][0],dp[j][0]+c1*(i-j-1));
}
if(b[j]<=a[i]&&a[j]<=b[i])
//(bj,aj)接到(ai,bi)前
{
dp[i][0]=min(dp[i][0],dp[j][1]+c1*(i-j-1));
}
}
for(ll j=0;j<=i-1;++j)
{
if(a[j]<=b[i]&&b[j]<=a[i])
//(aj,bj)接到(bi,ai)前
{
dp[i][1]=min(dp[i][1],dp[j][0]+c1*(i-j-1));
}
if(b[j]<=b[i]&&a[j]<=a[i])
//(bj,aj)接到(bi,ai)前
{
dp[i][1]=min(dp[i][1],dp[j][1]+c1*(i-j-1));
}
}
dp[i][1]+=c2;
ans=min(ans,min(dp[i][0],dp[i][1])+c1*(n-i));
}
cout<<ans<<'\n';
}
小鸡的排列构造checker
赛时我做这道题,交了一次,tle了。也想不到什么优化的方法所以就放掉了
赛后看题解,题解展示了一个名叫离线将查询排列的技巧,使用树状数组维护。

详见代码
点击查看代码
void solve() {
ll n,m;cin>>n>>m;
vector<ll>p(n+1),pos(n+1);
for(ll i=1;i<=n;++i)
{
cin>>p[i];
pos[p[i]]=i;
}
vector<vector<ll>> q(n+1);
vector<ll> l(m),r(m),c(m),ans(m);
for(ll i=0;i<m;i+=1)
{
cin>>l[i]>>r[i]>>c[i];
q[p[c[i]]].push_back(i);
}
vector<ll> bit(n+1); //树状数组
//树状数组每个节点bit[i]用来储存一个区间的累计值
auto add=[&](ll i)
{
//[&]是lambma的捕获列表
//add是接收一个整数i的函数,作用是将bit数组的i位置上的值+1
for( ;i<=n;i+=i&-i)bit[i]+=1;
};
auto sum=[&](ll i)
{
ll res=0;
for(;i;i-=i&-i)
/*
i-=i&-i是树状数组种常见操作,
通过低位的部分来递归地查询或更新数据结构地父节点
i&-i取的是i和-i按位与的结果,代表当前i位置的“步长”或“跨度”
*/
{
res+=bit[i];
}
return res;
};
for(ll i=1;i<=n;++i)
{
for(ll j:q[i])
{
ans[j]=sum(r[j])-sum(l[j]-1)+l[j];
}
add(pos[i]);
}
for(ll i:ans)
{
cout<<i<<'\n';
}
}
round 10
https://vjudge.net/contest/692274
C
思路:把每个ai加起来,求平方根,判断根是否为整数
判断是否整数代码
bool check(double x)
{
ll temp=static_cast<ll>(x);
return x==temp;
}
D
最开始做的那个版本结构有点模糊,绕来绕去的(感觉是substr用了两次并且没处理好),导致答案也错了。后面从头做了遍。
:因为从前往后的话,遇到的第一个元素是辅音,是无法判断是辅元辅还是辅元的。所以倒着来。如果倒数第二个数是辅音(题目已保障都能分割),那么就是辅元辅,last-=3;否则是辅元。依次存入开字符串类型的数组里。最后倒置数组,依次输出,并在每个字符串之后加'.'(除最后)
点击查看代码
bool check(char c)
{
//V
return c == 'a' || c == 'e';
}
void solve()
{
ll n;cin>>n;
string s;
vector<string> tmp;
string ans;
cin >> s;
ll last =n-1;
while(last>=0)
{
if(check(s[last]))
{
tmp.push_back(s.substr(last-1,2));
last -= 2;
}
else {
tmp.push_back(s.substr(last-2,3));
last -=3;
}
}
int len = tmp.size();
reverse(tmp.begin(), tmp.end());
for(ll i=0;i<len;++i)
{
ans+=tmp[i];
if(i!=len-1)
ans.push_back('.');
}
cout<<ans<<'\n';
}
E
赛时做出来差了几步,判断差值是否成立。
我们要使奇数索引的前缀和等于偶数索引的前缀和

点击查看代码
void solve()
{
ll n;cin>>n;
vector<ll>a={0};
ll oddpre[n+10]={0},evenpre[n+10]={0};
map<ll,bool>mp;
mp[0]=1;
oddpre[0]={0};
evenpre[0]={0};
for(ll i=1;i<=n;++i)
{
ll x;cin>>x;
a.push_back(x);
}
for(ll i=1;i<=n;++i)
{
oddpre[i]=oddpre[i-1];
evenpre[i]=evenpre[i-1];
if(i%2)
{
oddpre[i]+=a[i];
}else{
evenpre[i]+=a[i];
}
// cout<<oddpre[i]<<" "<<evenpre[i];
}
for(ll i=1;i<=n;++i)
{
ll temp=oddpre[i]-evenpre[i];
// cout<<temp<<'\n';
if(mp[temp])
{
cout<<"YES\n";
return;
}else{
mp[temp]=1;
}
}
cout<<"NO\n";
}
我自己补题的时候出错是,我求奇偶前缀和是直接oddpre[i]=oddpre[i-1]+a[i]的这会导致,无法正确的累加到前缀和
总结
上周画的饼还是大饼哈,除开身体方面这周有点毛病,但直接还是效率不够的问题。
这周补的牛客题居多,见识到了很多新的方法(之前也没见过什么方法哈)。
再次感受到自己动态规划学的之烂,,,补题的时候感觉又在学新的一样〒▽〒
下周就是最后一周了,希望效率高点,多多补题,还有回顾动态规划,有多时间学下主席树(牛客6的I题也能用这个做)

浙公网安备 33010602011771号