赛时AC:AB rating: 1167 补题:ABCD
比赛链接牛客周赛 Round 61
目录
A
输出十年后的今天,把字符串年转化为整型后+10;
但是我发现年分是2000-2024,不必这么麻烦。完全不用考虑逢十进一
虽然方法很多,但第一时间想到的方法都是好方法
字符串处理
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
const ll N=2e5+5;
const ll mod=1e9+7;
ll a[N];
void solve()
{
string s;
cin>>s;
string p=s.substr(0,4);
ll ans=stoi(p);
ans+=10;
cout<<ans;
for(int i=4;i<s.size();i++)
{
cout<<s[i];
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t=1;//cin>>t;
while(t--)
{
solve();
}
}
B
首先判断正方形,即也就是判断一个数是不是平方数;
判断平方数要特别注意
先把sqrt转化为整型,切勿sqrt*sqrt。可恨的是,曾经我就发现了这个细节,结果后来却又在这跌倒了一次。
可怕的时不是跌倒,怕的是跌倒爬起来的再次跌倒。
考虑等腰三角形时,我没多想,后来看题解才发现,整数边长的面积结果都必不为整数,因为分子有一个根号三。
真实结果只有0和3.
等边三角形s=(a²√3)/4 (a为边长)
要判断也是可以,同时平方消去根号三,在开四次方根 回带验证即可。
平方数判断,等边三角形面积公式
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
const ll N=2e5+5;
const ll mod=1e9+7;
ll a[N];
void solve()
{
ll s;
cin>>s;
ll op=0,po=0;
ll d=sqrt(s);
ll p=s*s;
p=p*16/3;
ll c1=sqrt(p);
c1=sqrt(c1);
if(d*d==s)
{
op=1;
}
if(c1*c1*c1*c1==p)
{
po=1;
}
if(op==1)
{
cout<<"0\n";
}
else
{
cout<<3<<'\n';
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t=1;cin>>t;
while(t--)
{
solve();
}
}
C
赛时因为一些组合数计数的性质,没能正确计数(或多或少了)
其实之前也遇到过类似的,但一直未去搞懂。今天来仔细讲一讲。
其实这题有三个子问题,之前都遇到过类似的,都是典型
先来说
第一个问题
删除部分达到我们的目的,其实就是看最坏情况下能不能到。
也就是不走回头路,由于初始点在(0,0),也不必分四个象限讨论。
只需判断x轴或y轴最小值就可以,最小都可以的话,最大也就可以。
ll n,x,y;
cin>>n>>x>>y;
ll cu=0,cd=0,cl=0,cr=0;
string s;cin>>s;s=" "+s;
for(int i=1;i<=n;i++)
{
if(s[i]=='U')
{
cu++;
}
if(s[i]=='D')
{
cd++;
}
if(s[i]=='L')
{
cl++;
}
if(s[i]=='R')
{
cr++;
}
}
ll op=max(cu,cd);
ll po=max(cl,cr);
if(op>=abs(x)&&po>=abs(y))
{
cout<<"YES ";
}
else
{
cout<<"NO\n";
return ;
}
第二个问题
要求我们输出路径,能到的话,肯定是不走回头路这种最坏情况都能到(最短路)。
直接贪心 遇到我们需要的路就先走 输出就可以
ll c[9]={0};
c[1]=abs(x);c[2]=abs(x);c[3]=abs(y);c[4]=abs(y);
ll f=0;
for(int i=1;i<=n;i++)
{
if(c[1]&&s[i]=='U'&&x>0)
{
cout<<"U";
c[1]--;
}
else if(c[2]&&s[i]=='D'&&x<0)
{
cout<<"D";
c[2]--;
}
else if(c[3]&&s[i]=='L'&&y<0)
{
cout<<"L";
c[3]--;
}
else if(c[4]&&s[i]=='R'&&y>0)
{
cout<<"R";
c[4]--;
}
}
第三个问题
接下来是本题重点研究的部分
由于本次研究重点不是组合数,而是关于组合数的计数,因此求组合数代码直接给出模版
组合数模版
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
const ll N=1e5+5;
const ll p=1e9+7;
ll a[N];
ll jc[N+5],inv[N+5],pw[N+5];
ll ksm(ll a,ll b)
{
ll ans=1;
a%=p;
while(b)
{
if(b&1)
{
ans=ans*a%p;//错过一次
}
a=a*a%p;
b>>=1;
}
return ans;
}
void init()
{
jc[0]=inv[0]=pw[0]=1;
for(int i=1;i<=N;i++)
{
jc[i]=jc[i-1]*i%p;
}
inv[N]=ksm(jc[N],p-2);
for(int i=N-1;i>=1;i--)
{
inv[i]=inv[i+1]*(i+1)%p;
}
}
ll C(ll n,ll m)//cnm
{
if(n<m||n<0||m<0)
{
return 0;
}
return jc[n]*inv[m]%p*inv[n-m]%p;//inv[m]是m!取模p的逆元
}
计数分析
其实在水平方向,沿同一方向有x个该方向是必选的。
其实在垂直方向,沿同一方向有y个该方向是必选的。
当我们这个方向多选一个,我们就要选一个反方向的一个,此时是一种情况,但实现该情况是有多个操作方法的。
分四种情况讨论就行了
计数取模特别提醒
加过后再单独取模
要下面这样
ret+=C(cr,i-y)*C(cl,i);
ret%=p;
而不是这样
ret+=C(cr,i-y)*C(cl,i)%p;
ll res=0,ret=0;
if(x>=0)
{
for(int i=x;i<=cu;i++)
{
if(i-x>cd)
break;
res+=C(cu,i)*C(cd,i-x);
res%=p;
}
}
else
{
x=-x;
for(int i=x;i<=cd;i++)
{
if(i-x>cu)
break;
res+=C(cu,i-x)*C(cd,i);
res%=p;
}
}
//cout<<res;
if(y>=0)
{
for(int i=y;i<=cr;i++)
{
if(i-y>cl)
break;
ret+=C(cr,i)*C(cl,i-y);
ret%=p;
}
}
else
{
y=-y;
for(int i=y;i<=cl;i++)
{
if(i-y>cr)
break;
ret+=C(cr,i-y)*C(cl,i);
ret%=p;
}
}
ll ans=res%p*ret%p;
cout<<ans;
cout<<"\n";
二维平面移动可达性判断、组合数计数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
const ll N=1e5+5;
const ll p=1e9+7;
ll a[N];
ll jc[N+5],inv[N+5],pw[N+5];
ll ksm(ll a,ll b)
{
ll ans=1;
a%=p;
while(b)
{
if(b&1)
{
ans=ans*a%p;//错过一次
}
a=a*a%p;
b>>=1;
}
return ans;
}
void init()
{
jc[0]=inv[0]=pw[0]=1;
for(int i=1;i<=N;i++)
{
jc[i]=jc[i-1]*i%p;
}
inv[N]=ksm(jc[N],p-2);
for(int i=N-1;i>=1;i--)
{
inv[i]=inv[i+1]*(i+1)%p;
}
}
ll C(ll n,ll m)//cnm
{
if(n<m||n<0||m<0)
{
return 0;
}
return jc[n]*inv[m]%p*inv[n-m]%p;//inv[m]是m!取模p的逆元
}
void solve()
{
ll n,x,y;
cin>>n>>x>>y;
ll cu=0,cd=0,cl=0,cr=0;
string s;cin>>s;s=" "+s;
for(int i=1;i<=n;i++)
{
if(s[i]=='U')
{
cu++;
}
if(s[i]=='D')
{
cd++;
}
if(s[i]=='L')
{
cl++;
}
if(s[i]=='R')
{
cr++;
}
}
ll op=max(cu,cd);
ll po=max(cl,cr);
if(op>=abs(x)&&po>=abs(y))
{
cout<<"YES ";
}
else
{
cout<<"NO\n";
return ;
}
init();
ll c[9]={0};
c[1]=abs(x);c[2]=abs(x);c[3]=abs(y);c[4]=abs(y);
ll f=0;
for(int i=1;i<=n;i++)
{
if(c[1]&&s[i]=='U'&&x>0)
{
cout<<"U";
c[1]--;
}
else if(c[2]&&s[i]=='D'&&x<0)
{
cout<<"D";
c[2]--;
}
else if(c[3]&&s[i]=='L'&&y<0)
{
cout<<"L";
c[3]--;
}
else if(c[4]&&s[i]=='R'&&y>0)
{
cout<<"R";
c[4]--;
}
}
cout<<" ";
ll res=0,ret=0;
if(x>=0)
{
for(int i=x;i<=cu;i++)
{
if(i-x>cd)
break;
res+=C(cu,i)*C(cd,i-x);
res%=p;
}
}
else
{
x=-x;
for(int i=x;i<=cd;i++)
{
if(i-x>cu)
break;
res+=C(cu,i-x)*C(cd,i);
res%=p;
}
}
//cout<<res;
if(y>=0)
{
for(int i=y;i<=cr;i++)
{
if(i-y>cl)
break;
ret+=C(cr,i)*C(cl,i-y);
ret%=p;
}
}
else
{
y=-y;
for(int i=y;i<=cl;i++)
{
if(i-y>cr)
break;
ret+=C(cr,i-y)*C(cl,i);
ret%=p;
}
}
ll ans=res%p*ret%p;
cout<<ans;
cout<<"\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t=1;cin>>t;
while(t--)
{
solve();
}
}
D
由于原数组是单调递增的,不难想到和中间那个数有关系