目录
A.Letter Song ~ 致十年后的我们
(https://ac.nowcoder.com/acm/contest/91072/A)
1.思路 (AC ^ ^)
将字符串的年份转化为整型+10后再转化为字符串输出
2.函数
(1)截取指定长度的字符串,前开后闭
string s = "2024-9-22";
string re = s.substr(0,4); // "2024"
(2)将字符串转化为整数
string s = "2024"; // std::意思是特定命名空间,stoi(string to integer)
int year = std::stoi(s); // 2024
(3)将整数转化为字符串
int year = 2024;
string re = std::to_string(year); // "2024"
B.简单图形问题 - 0123
(https://ac.nowcoder.com/acm/contest/91072/B)
1.思路 (AC ^ ^)
根据面积直接算边长,判断是否为整数(等边三角形面积 )
2.函数
(1)判断一个数是否为整数,小数+整数和整数部分的差值是否小于某个阈值
bool whe(x){
const double ep = 1e-9; // 1e-9 = 1*10^-9
return fabs(x - floor(x)) < ep; // fabs计算浮点数的绝对值,floor计算<=x最大整数
}
3.其他
只有两种可能,要么是0,要么是3,因为题目给出的面积s为整数,所以不可能是等边三角形,只要判断所给出的面积能否构成正方形即可
C.小红的机器人构造 - Ⅰ+Ⅱ+Ⅲ
(https://ac.nowcoder.com/acm/contest/91072/C)
1.思路
Ⅰ x轴、y轴两个方向独立,只要到达(x,y)对应的方向上的步数足够即可,如x=3,y=2,U>=3&&R>=2即可,注意这里的x=3,y=2对应坐标轴是(2,3)
Ⅱ 因为已经确定可以到达相应的位置,直接输出正好到达该位置的步数即可,如x=3,y=2,输出UUURR(举个例子,并非一定是这样),其他舍去
Ⅲ 需要利用组合数的相关知识进行求解,先求解y方向上的所有可能
利用for循环枚举所有的可能,假设D删除i步,U删除j步, 则所有可能情况为:C(U,j)*C(D,i)
假设x>0,需满足:(U-j)-(D-i)= x 即:j = U - D + i -x 即:U-j = D + x - i
假设x>0,需满足:(D-i)-(U-j)= -x 即:j = U - D +i -x 即:U-j = D + x - i
for(int i=0;i<=n;i++){
ansx+=C(ctu,ctd+x-i)*C(ctd,i)%mod;
ansy+=C(ctr,ctl+y-i)*C(ctl,i)%mod;
}
发现结果相同,因此不必分开讨论x的情况来计算,因为组合数中C(U,j)与C(U,U-j)等价的,所以最终结果就是:C(U,D+x-i)*C(D,i)
这里为什么是D删除i步,而不是U呢,其实都可以,看自己的喜好,再假设U删i步,D删j步
假设x>0,需满足:(U-i)- (D-j)= x 即:j = x + i + D - U 即:D-j = U - x - i
假设x<0,需满足:(D-j)-(U-i)= -x 即:j = x + i + D - U 即:D-j = U - x - i
for(int i=0;i<=n;i++){
ansx+=C(ctu,i)*C(ctd,ctu-x-i)%mod;
ansy+=C(ctr,i)*C(ctl,ctr-y-i)%mod;
}
x方向的结果以及结论类似,求解后把两个情况相乘(求解过程注意保证%mod,避免结果溢出)
2.函数
(1)快速幂函数,即求a^b(a的b次方)
int qpow(int a, int b){
int t = 1;
int y = a;
while(b){
if(b&1){
t = (t*y)%mod;
}
y = (y*y)%mod;
b>>=1; // 向右移一位,相当于b/=2
}
return t;
}
(2)利用逆元求解组合数
const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N]; // a[i]表示i的阶层,b[i]表示i的逆元
void init(){
int n = 1e6;
a[0]=1;
b[0]=1;
for(int i=1;i<=n;i++){
a[i] = a[i-1]*i%mod;
} // 利用费马小定理求解n!的逆元x
b[n] = qpow(a[n],mod-2); // n!*x 三 1 (mod p) n!^p-1 三 1 (mod p)
for(int i=n-1;i>=1;i--){ // n!*x 三 n!^n-1 x 三 n!^p-2
b[i] = b[i+1]*(i+1)%mod; // n!的逆元为n!^(mod-2) (n-1)!的逆元为n*n!^(mod-2)
}
}
int C(int m, int n){
if(n>=0&&m>=n){
return a[m]*b[n]%mod*b[m-n]%mod; // 两个阶层相乘后就要取mod防止溢出
}else{
return 0;
}
}
1>什么是逆元:如果一个线性同余方程ax 三 1(mod b),称x为 a mod b 的逆元;即一个数有逆元x,除以这个数a,相当于乘以x
2>费马小定理:若p为质数,a为正整数,且a、p互质,则a^p-1 三 1 (mod p)
3>C(m,n) = m! / (m-n)! * n!
3.完整代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N];
int qpow(int a, int b){
int t = 1;
int y = a;
while(b){
if(b&1){
t = (t*y)%mod;
}
y = (y*y)%mod;
b>>=1;
}
return t;
}
const int mod = 1e9+7,N = 1e6+10;
int a[N],b[N];
void init(){
int n = 1e6;
a[0]=1;
b[0]=1;
for(int i=1;i<=n;i++){
a[i] = a[i-1]*i%mod;
}
b[n] = qpow(a[n],mod-2);
for(int i=n-1;i>=1;i--){
b[i] = b[i+1]*(i+1)%mod;
}
}
int C(int m, int n){
if(n>=0&&m>=n){
return a[m]*b[n]%mod*b[m-n]%mod;
}else{
return 0;
}
}
void solve(){
int n,x,y,nx,ny;
cin>>n>>x>>y;
string s;
cin>>s;
int ctu=0,ctd=0,ctl=0,ctr=0;
for(auto c:s){
if(c=='U')ctu++;
if(c=='D')ctd++;
if(c=='L')ctl++;
if(c=='R')ctr++;
}
if(x>0&&ctu<x){cout<<"NO"<<endl; return ;}
if(x<0&&ctd<-x){cout<<"NO"<<endl; return ;}
if(y>0&&ctr<y){cout<<"NO"<<endl; return ;}
if(y<0&&ctl<-y){cout<<"NO"<<endl; return ;}
cout<<"YES ";
nx = x;
ny = y;
for(auto c:s){
if(nx>0&&c=='U'){nx--,cout<<"U";}
if(nx<0&&c=='D'){nx++,cout<<"D";}
if(ny>0&&c=='R'){ny--,cout<<"R";}
if(ny<0&&c=='L'){ny++,cout<<"L";}
}
int ansx=0,ansy=0;
for(int i=0;i<=n;i++){
ansx+=C(ctu,i)*C(ctd,ctu-x-i)%mod;
ansy+=C(ctr,i)*C(ctl,ctr-y-i)%mod;
}
ansx%=mod;
ansy%=mod;
cout<<" "<<ansx*ansy%mod<<endl;
}
signed main(){
init();
int t;
cin>>t;
while(t--){
solve();
}
}
D.小红的差值构造 - easy+hard+extreme
(https://ac.nowcoder.com/acm/contest/91072/D)
1.思路
当l<=n的时候,让x和y在数组n的中心mid处,对称分布在mid的左右两侧时,f最小
当l>n的时候,让x分布在中心mid处,y在x+l处,可使得,f最小
在计算f的时候需要计算三个区间,即x的左侧,y的右侧和x、y之间的区间
当l<=n时,x的左侧和y的右侧都是等差数列,直接计算即可。x、y之间的区间,元素个数为偶数时,就是两个等差数列,元素个数为奇数时,是中间元素+两个等差数列
当l>n时,可以得出y一定是在n元素的右侧且x、y之间的元素都是距x更近,所以要计算的区间剩下x的左侧和x、y之间。x的左侧就是等差数列直接计算,x的右侧也是等差数列直接计算
2.函数
(1)计算等差数列前n项和(x可能在0处,因此x左侧元素值无需计算返回0)
int cal(int x){
if(x<=0){
return 0;
}
return (1+x)*x/2;
}
(2)计算x、y之间元素和
int calmid(int x){ // 元素个数
int mid = x/2+x%2;
if(x%2!=0){
return mid+2*cal(mid-1);
}else{
return 2*cal(mid);
}
}
3.完整代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int cal(int x){
if(x<=0){
return 0;
}
return (1+x)*x/2;
}
int calmid(int x){
int mid = x/2+x%2;
if(x%2!=0){
return mid+2*cal(mid-1);
}else{
return 2*cal(mid);
}
}
void solve(){
int n,l;
cin>>n>>l;
int mid = n/2+n%2;
if(n>=l){
int x = mid - l/2;
int y = x + l;
cout<<x<<" "<<y<<" "<<calmid(y-x-1)+cal(x-1)+cal(n-y)<<endl;
}else{
int x = mid;
int y = mid + l;
cout<<x<<" "<<y<<" "<<cal(x-1)+cal(n-x)<<endl;
}
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
}