【题解/标程】2022牛客寒假算法基础集训营 1 题解+标程
题解pdf现在在群(477641458)的群文件中(更新:群满了,现在进975214176),过几天也会把题解挂到这个帖子里。
更新:题解pdf
更新:B站讲题视频
这里主要给出一些标程,来自于我或某位验题人(有的题我的代码太丑陋了,就放验题人的了),欢迎对照题解查看。
#include<bits/stdc++.h>
#define fors(i,a,b) for(int i = a; i < b; ++i)
#define ll long long
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
const int maxn = 1e5+5;
int f[maxn][9];
const int mod = 998244353;
int main(){
int n; cin>>n;
f[0][0] = 1;
fors(i,1,n+1){
int x; scanf("%d", &x); x %= 9;
fors(j,0,9){
f[i][(j+x)%9] = (f[i][(j+x)%9] + f[i-1][j])%mod;
f[i][j] = (f[i][j]+f[i-1][j])%mod;
}
}
fors(i,1,9) cout<<f[n][i]<<" "; cout<<f[n][0]-1<<endl;
return 0;
}DP数组含义与题解中相同。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair pii;
int n,q,st[3][200010][21];
char s[200010];
int mod3(int x){
return (x%3+3)%3;
}
int main(){
cin>>n>>q;
scanf("%s",s+1);
rep(j,0,20){
rep(i,1,n){
if(j==0){
if(s[i]=='W'){
st[0][i][j]=st[1][i][j]=st[2][i][j]=1;
}
if(s[i]=='L'){
st[1][i][j]=st[2][i][j]=-1;
st[0][i][j]=0;
}
if(s[i]=='D'){
st[0][i][j]=st[1][i][j]=st[2][i][j]=0;
}
}
else{
int p1=i,p2=i+(1<<(j-1));
if(p2>n){
st[0][p1][j]=st[0][p1][j-1];
st[1][p1][j]=st[1][p1][j-1];
st[2][p1][j]=st[2][p1][j-1];
}
else{
st[0][p1][j]=st[0][p1][j-1]+st[mod3(0+st[0][p1][j-1])][p2][j-1];
st[1][p1][j]=st[1][p1][j-1]+st[mod3(1+st[1][p1][j-1])][p2][j-1];
st[2][p1][j]=st[2][p1][j-1]+st[mod3(2+st[2][p1][j-1])][p2][j-1];
}
}
}
}
int l,r,ans;
rep(_,1,q){
scanf("%d%d%d",&l,&r,&ans);
int pos=l;
while(pos<=r){
int j=0;
while(pos+(1<<j)-1<=r) j++;
j--;
ans+=st[ans%3][pos][j];
pos+=(1<<j);
}
printf("%d\n",ans);
}
return 0;
}st数组含义与题解相同,rep是上面宏定义的for()循环简写(希望你不是很讨厌这种写法)。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int n,le[110],a[110][5],res[1010],p;
int main(){
cin>>n;
rep(i,1,n){
le[i]=4;
rep(j,1,3){
scanf("%d",&a[i][j]);
if(a[i][j]) le[i]=min(le[i],j);
}
}
rep(i,1,n){
if(le[i]!=4){
int j=p;
while(res[j]!=i-le[i]) j--;
// printf("%d %d\n",i,j);
int add=3-(p-j);
rep(j,1,add) res[++p]=0;
}
res[++p]=i;
}
printf("%d\n",p-n);
return 0;
}res[]数组维护新的程序,res[i]=0表示这是一条空语句,否则res[i]=x表示这是源程序中第x条语句。
D 牛牛做数论
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41};
ll n,t;
inline bool isP(int x){
if(x<=3) return true;
for(int i=2;i*i<=n;i++){
if(n%i==0) return false;
}
return true;
}
int main(){
cin>>t;
while(t--){
cin>>n;
assert(n!=0);
ll now=1,i=1;
if(n==1){
puts("-1");
continue;
}
while(now*prime[i]<=n){
now*=prime[i];
i++;
}
printf("%lld ",now);
while(!isP(n)){
n--;
}
printf("%lld\n",n);
}
return 0;
} #include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int T,n,m;
int main(){
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
if(m==1){
if(n==1) puts("1");
else puts("-1");
}
else{
printf("%d\n",((n-1)/(m-1)+((n-1)%(m-1)!=0))*2-1);
}
}
return 0;
}F 中位数切分
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int T,n,m;
int a[100010];
int main(){
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
int ans=0;
rep(i,1,n){
scanf("%d",&a[i]);
if(a[i]>=m) ans++;
else ans--;
}
if(ans>0) printf("%d\n",ans);
else puts("-1");
}
return 0;
}↑题解中的简单方法;
#include<bits/stdc++.h>
using ll = long long;
using ld = long double;
namespace GTI
{
char gc(void)
{
const int S = 1 << 16;
static char buf[S], *s = buf, *t = buf;
if (s == t) t = buf + fread(s = buf, 1, S, stdin);
if (s == t) return EOF;
return *s++;
}
ll gti(void)
{
ll a = 0, b = 1, c = gc();
for (; !isdigit(c); c = gc()) b ^= (c == '-');
for (; isdigit(c); c = gc()) a = a * 10 + c - '0';
return b ? a : -a;
}
int gts(char *s)
{
int len = 0, c = gc();
for (; isspace(c); c = gc());
for (; c != EOF && !isspace(c); c = gc()) s[len++] = c;
s[len] = 0;
return len;
}
int gtl(char *s)
{
int len = 0, c = gc();
for (; isspace(c); c = gc());
for (; c != EOF && c != '\n'; c = gc()) s[len++] = c;
s[len] = 0;
return len;
}
}
using GTI::gti;
using GTI::gts;
using GTI::gtl;
const int inf = 0x3f3f3f3f;
struct BIT
{
std::vector<int> f;
int n;
void init(int n)
{
this->n = n;
f.resize(n);
std::fill(f.begin(), f.end(), -inf);
}
void insert(int loc, int val)
{
if (loc == 0) f[0] = std::max(f[0], val);
else
for (int i = loc; i < n; i += i & -i)
f[i] = std::max(f[i], val);
}
int query(int loc)
{
if (loc < 0) return -inf;
int ret = f[0];
for (int i = loc; i; i -= i & -i)
ret = std::max(ret, f[i]);
return ret;
}
}tr;
const int N = 1e5 + 500;
int a[N], f[N];
int main(void)
{
for (int T = gti(); T; T--)
{
int n = gti(), m = gti();
for (int i = 1; i <= n; i++)
a[i] = (gti() >= m ? 1 : -1) + a[i - 1];
{
std::vector<int> val;
for (int i = 0; i <= n; i++)
val.push_back(a[i]);
std::sort(val.begin(), val.end());
val.erase(std::unique(val.begin(), val.end()), val.end());
for (int i = 0; i <= n; i++)
a[i] = lower_bound(val.begin(), val.end(), a[i]) - val.begin();
tr.init(val.size());
}
tr.insert(a[0], 0);
for (int i = 1; i <= n; i++)
{
f[i] = tr.query(a[i] - 1) + 1;
tr.insert(a[i], f[i]);
}
if (f[n] < 0) puts("-1");
else printf("%d\n", f[n]);
}
return 0;
}↑题解中树状数组优化dp的麻烦方法。
#include<bits/stdc++.h>
#define fors(i,a,b) for(int i = a; i < b; ++i)
#define ll long long
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
int sg(int x){
if(x == 0) return 0;
if(x<0) return -1;
return 1;
}
int main(){
int T; cin>>T; assert(T <= 1e4 && T > 0);
int sumn = 0;
while(T--){
int n; scanf("%d", &n); sumn += n;
assert(n <= 1e5 && n > 0);
vector<int> f(n);
fors(i,0,n) scanf("%d", &f[i]);
vector<int> t1, t2;
vector<int> cc;
int cnt = 0;
fors(i,1,n-1){
if(f[i]>f[i-1] && f[i]>f[i+1]){
int d = f[i]-max(f[i-1], f[i+1]);
int up = max(f[i-1],f[i+1]) + d/2+1;
t1.pb(up); cc.pb(up);
}
else if(f[i] < min(f[i-1], f[i+1]) ) {
int d = min(f[i-1], f[i+1])-f[i];
int up = f[i]+(d+1)/2;
t2.pb(up); cc.pb(up);
cnt++;
}else if(min(f[i-1], f[i+1]) < f[i] && max(f[i-1], f[i+1]) > f[i] ){
int l = min(f[i-1], f[i+1]);
int r = max(f[i-1], f[i+1]);
int L = l+ (f[i]-l)/2 + 1;
int R = f[i]+(r-f[i]+1)/2;
if(L <= R) {t1.pb(L), t2.pb(R);}
}
}
for(int x:t1) cc.pb(x); for(int x:t2) cc.pb(x);
sort(all(cc)); cc.erase(unique(all(cc)), cc.end());
vector<int> d(cc.size());
for(int x:t1){
// cout<<"x1:"<<x<<endl;
int p = lower_bound(all(cc), x)-cc.begin(); d[p]++;
}
for(int x:t2){
// cout<<"x2:"<<x<<endl;
int p = lower_bound(all(cc), x)-cc.begin(); d[p]--;
}
int ans = cnt;
fors(i,1,d.size()) d[i]+=d[i-1];
for(int x:d) ans = min(ans, cnt+x);
cout<<ans<<endl;
}
assert(sumn <= 1e6 && sumn > 0);
return 0;
}这里是将题解中提到预处理出来的所有区间的
放到
中、
放到
中,然后解区间覆盖问题。
H 牛牛看云
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int n;
int a[1000010];
ll cnt[1010];
int main(){
cin>>n;
rep(i,1,n){
scanf("%d",&a[i]);
cnt[a[i]]++;
}
ll ans=0;
rep(i,0,1000){
rep(j,i,1000){
ll add;
if(i==j) add=(cnt[i]+cnt[i]*(cnt[i]-1ll)/2ll);
else add=cnt[i]*cnt[j];
ans=ans+add*(ll)abs(i+j-1000);
}
}
printf("%lld\n",ans);
return 0;
}add表示当前的(i,j)对儿贡献了多少次。
I B站与各唱各的
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int P = 1000000007;
int ksm(int x,int k) {
int ans=1;
while (k) {
if (k&1) ans=1ll*ans*x%P;
x=1ll*x*x%P;
k>>=1;
}
return ans;
}
int inv(int x) {
return ksm(x,P-2);
}
void solve()
{
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",1ll*(ksm(2,n-1)-1)*inv(ksm(2,n-1))%P*m%P);
}
int main()
{
int t;
scanf("%d",&t);
while (t--) solve();
}J 小朋友做游戏
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int T,A,B,n;
int va[10010],vb[10010];
bool cmp(int xx,int yy){
return xx>yy;
}
int suma[10010],sumb[10010];
int main(){
cin>>T;
while(T--){
cin>>A>>B>>n;
rep(i,1,A) scanf("%d",&va[i]);
rep(i,1,B) scanf("%d",&vb[i]);
int mxb=min(n/2,B);
if(A+mxb<n){
puts("-1");
continue;
}
sort(va+1,va+1+A,cmp);
sort(vb+1,vb+1+B,cmp);
rep(i,1,A) suma[i]=suma[i-1]+va[i];
rep(i,1,B) sumb[i]=sumb[i-1]+vb[i];
int ans=-1;
rep(ia,0,A){
int ib=n-ia;
if(ib>mxb||ib<0) continue;
ans=max(ans,suma[ia]+sumb[ib]);
}
assert(ans!=-1);
printf("%d\n",ans);
}
return 0;
}
K 冒险公社
简约美版本:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int n;
// 0G 1B 2R
int dp[100010][27];
const int inf=-1e6;
char s[100010];
int cnt(int x){
int g=(x%3==0)+(x/3%3==0)+(x/9%3==0);
int r=(x%3==2)+(x/3%3==2)+(x/9%3==2);
return g-r;
}
int main(){
scanf("%d%s",&n,s+1);
rep(i,0,n+5){
rep(j,0,26) dp[i][j]=inf;
}
rep(j,0,26){
if(s[3]=='G'&&cnt(j)<=0) continue;
if(s[3]=='B'&&cnt(j)!=0) continue;
if(s[3]=='R'&&cnt(j)>=0) continue;
dp[3][j]=(j%3==0)+(j/3%3==0)+(j/9%3==0);
}
rep(i,4,n){
rep(j,0,26){
if(s[i]=='G'&&cnt(j)<=0) continue;
if(s[i]=='B'&&cnt(j)!=0) continue;
if(s[i]=='R'&&cnt(j)>=0) continue;
rep(k,0,26){
if(k%3==j/3%3&&k/3%3==j/9%3){
dp[i][j]=max(dp[i][j],dp[i-1][k]+(j%3==0));
}
}
}
}
int ans=inf;
rep(j,0,26) ans=max(ans,dp[n][j]);
if(ans<0) puts("-1");
else printf("%d\n",ans);
return 0;
}暴力美学版本:
#include<iostream>
#include<string.h>
using namespace std;
int f[100010][4][4][4];//在i前三个为j k p的绿色个数
int main()
{
int n;
string s;
cin>>n;
cin>>s;
s=" "+s;
// hei hong lv
memset(f,-1,sizeof f);
if(s[n]=='G')
{
f[n][1][1][1]=3;
f[n][1][1][3]=2;
f[n][1][3][1]=2;
f[n][3][1][1]=2;
f[n][1][1][2]=2;
f[n][1][2][1]=2;
f[n][2][1][1]=2;
f[n][1][3][3]=1;
f[n][3][1][3]=1;
f[n][3][3][1]=1;
}
if(s[n]=='R')
{
f[n][2][2][2]=0;
f[n][2][2][3]=0;
f[n][2][3][2]=0;
f[n][3][2][2]=0;
f[n][2][2][1]=1;
f[n][2][1][2]=1;
f[n][1][2][2]=1;
f[n][2][3][3]=0;
f[n][3][2][3]=0;
f[n][3][3][2]=0;
}
if(s[n]=='B')
{
f[n][3][3][3]=0;
f[n][3][1][2]=1;
f[n][3][2][1]=1;
f[n][1][3][2]=1;
f[n][2][3][1]=1;
f[n][2][1][3]=1;
f[n][1][2][3]=1;
}
for(int i=n-1;i>=3;i--)
{
if(s[i]=='G')
{
for(int j=1;j<=3;j++)
{
if(f[i+1][1][1][j]!=-1)f[i][1][1][1]=max(f[i][1][1][1],f[i+1][1][1][j]+1);
if(f[i+1][1][3][j]!=-1)f[i][1][1][3]=max(f[i][1][1][3],f[i+1][1][3][j]+1);
if(f[i+1][3][1][j]!=-1)f[i][1][3][1]=max(f[i][1][3][1],f[i+1][3][1][j]+1);
if(f[i+1][1][1][j]!=-1)f[i][3][1][1]=max(f[i][3][1][1],f[i+1][1][1][j]);
if(f[i+1][1][2][j]!=-1)f[i][1][1][2]=max(f[i][1][1][2],f[i+1][1][2][j]+1);
if(f[i+1][2][1][j]!=-1)f[i][1][2][1]=max(f[i][1][2][1],f[i+1][2][1][j]+1);
if(f[i+1][1][1][j]!=-1)f[i][2][1][1]=max(f[i][2][1][1],f[i+1][1][1][j]);
if(f[i+1][3][3][j]!=-1)f[i][1][3][3]=max(f[i][1][3][3],f[i+1][3][3][j]+1);
if(f[i+1][1][3][j]!=-1)f[i][3][1][3]=max(f[i][3][1][3],f[i+1][1][3][j]);
if(f[i+1][3][1][j]!=-1)f[i][3][3][1]=max(f[i][3][3][1],f[i+1][3][1][j]);
}
}
if(s[i]=='R')
{
for(int j=1;j<=3;j++)
{
if(f[i+1][2][2][j]!=-1)f[i][2][2][2]=max(f[i][2][2][2],f[i+1][2][2][j]+0);
if(f[i+1][2][3][j]!=-1)f[i][2][2][3]=max(f[i][2][2][3],f[i+1][2][3][j]+0);
if(f[i+1][3][2][j]!=-1)f[i][2][3][2]=max(f[i][2][3][2],f[i+1][3][2][j]+0);
if(f[i+1][2][2][j]!=-1)f[i][3][2][2]=max(f[i][3][2][2],f[i+1][2][2][j]+0);
if(f[i+1][2][1][j]!=-1)f[i][2][2][1]=max(f[i][2][2][1],f[i+1][2][1][j]);
if(f[i+1][1][2][j]!=-1)f[i][2][1][2]=max(f[i][2][1][2],f[i+1][1][2][j]);
if(f[i+1][2][2][j]!=-1)f[i][1][2][2]=max(f[i][1][2][2],f[i+1][2][2][j]+1);
if(f[i+1][3][3][j]!=-1)f[i][2][3][3]=max(f[i][2][3][3],f[i+1][3][3][j]+0);
if(f[i+1][2][3][j]!=-1)f[i][3][2][3]=max(f[i][3][2][3],f[i+1][2][3][j]+0);
if(f[i+1][3][2][j]!=-1)f[i][3][3][2]=max(f[i][3][3][2],f[i+1][3][2][j]+0);
}
}
if(s[i]=='B')
{
for(int j=1;j<=3;j++)
{
if(f[i+1][3][3][j]!=-1)f[i][3][3][3]=max(f[i][3][3][3],f[i+1][3][3][j]);
if(f[i+1][1][2][j]!=-1)f[i][3][1][2]=max(f[i][3][1][2],f[i+1][1][2][j]);
if(f[i+1][2][1][j]!=-1)f[i][3][2][1]=max(f[i][3][2][1],f[i+1][2][1][j]);
if(f[i+1][3][2][j]!=-1)f[i][1][3][2]=max(f[i][1][3][2],f[i+1][3][2][j]+1);
if(f[i+1][3][1][j]!=-1)f[i][2][3][1]=max(f[i][2][3][1],f[i+1][3][1][j]);
if(f[i+1][1][3][j]!=-1)f[i][2][1][3]=max(f[i][2][1][3],f[i+1][1][3][j]);
if(f[i+1][2][3][j]!=-1)f[i][1][2][3]=max(f[i][1][2][3],f[i+1][2][3][j]+1);
}
}
}
int ans=-1;
for(int i=0;i<=3;i++)
for(int j=0;j<=3;j++)
for(int p=0;p<=3;p++)
ans=max(ans,f[3][i][j][p]);
cout<<ans<<endl;
}L 牛牛学走路
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int T,n;
char s[1010];
int main(){
cin>>T;
while(T--){
scanf("%d%s",&n,s+1);
int x=0,y=0;
db ans=0;
rep(i,1,n){
if(s[i]=='U') y++;
if(s[i]=='D') y--;
if(s[i]=='L') x--;
if(s[i]=='R') x++;
ans=max(ans,hypot(x,y));
}
printf("%.12lf\n",ans);
}
return 0;
}