牛客题集:练习赛69、70
练习赛70
A
尺取即可
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} map<char ,int > mapp; string ss="puleyaknoi"; char s[maxn]; bool check(){ for (int i = 0; i <= 9; ++i) { if (mapp[ss[i]]==0) return false; } return true; } int t,n,l,r,ans; int main() { #ifndef ONLINE_JUDGE debug; #endif t=read(); while (t--) { scanf("%s",s+1); n=strlen(s+1); l=r=1; mapp.clear(); mapp[s[1]]=1; ans=INF; while (r<=n) { if (check()) { ans=min(ans,r-l+1); mapp[s[l]]--; l++; } else { r++; mapp[s[r]]++; } } cout << (ans==INF?-1:ans) <<endl; } return 0; }
B
因为题目的要求,字符串每个字母要按顺序出现,那我们只需找到一个字母,再从这个字母位置往后查找下一个字母,每次查找都用二分即可。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} string ss="puleyaknoi"; char s[maxn]; int a[maxn][27],ans,n,t,l,r,mid,now,mao; int main() { #ifndef ONLINE_JUDGE debug; #endif t=read(); while (t--) { scanf("%s",s+1); n=strlen(s+1); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= 26; ++j) { a[i][j]=a[i-1][j]; } a[i][s[i]-'a'+1]++; } for (int j = 1; j <= 26; ++j) a[n+1][j]=a[n][j]+1; ans=INF; for (int i = 1; i <= n; ++i) { now = 0; if (s[i]=='p') { l=i; for (int j = 1; j <= 9; ++j) { r=n; mao=l; while (l<=r) { mid=(l+r)/2; if (a[mid][ss[j]-'a'+1]>=a[mao][ss[j]-'a'+1]+1) r=mid-1; else l=mid+1; } if (l==n+1) { now=0; break; } else now=max(now,l-i+1); } if (now!=0) ans= min(ans,now); } } cout << (ans==INF?-1:ans) <<endl; } return 0; }
D
用个map记录每次增加的边,同时记录下每个点的出现次数,如果要删去一条边,map可以直接查询是否存在这条边,存在则判断点的出现次数,如果两个点都存在树中 ,说明删掉这条边还存在其他边把他们连起来,树的个数不变;如果两个点都只出现 1 次,说明两个点都只靠这条边连起来形成一颗树,删掉则树的个数 -1。如果要增添一条边,两条边都没出现过的话,树的个数 +1;都存在树中的话,说明两颗树会被合并成一颗树,树的个数 -1.
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<int, int> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} int du[maxn],t,op,u,v,id,x,y,ans; map<pii,int> mapp; map<int,int> vis; int main() { #ifndef ONLINE_JUDGE debug; #endif t=read(); while (t--) { op=read(); if (op==1) { u=read(),v=read(); if (!mapp[{u,v}]) { mapp[{u,v}]=mapp[{v,u}]=1; if (!vis[u]) vis[u]=++id; if (!vis[v]) vis[v]=++id; x=vis[u],y=vis[v]; if (du[x]==0 && du[y]==0) ans++; else if (du[x] && du[y]) ans--; du[x]++,du[y]++; } }else if (op==2) { u=read(),v=read(); if (mapp[{u,v}]) { mapp[{u,v}]=mapp[{v,u}]=0; x=vis[u],y=vis[v]; du[x]--,du[y]--; if (du[x]==0 && du[y]==0) ans--; else if (du[x] && du[y]) ans++; } }else { cout << ans <<endl; } } return 0; }
练习赛69
B
排个序,把最大的几个都挑出来,总能把这几个数分组
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} int n,a[maxn],x,y; ll sum[maxn],ans; int main() { #ifndef ONLINE_JUDGE debug; #endif n=read(); for (int i = 1; i <= n; ++i) { a[i]=read(); } sort(a+1,a+1+n); reverse(a+1,a+1+n); for (int i = 1; i <= n; ++i) { sum[i]=sum[i-1]+a[i]; } x=read(),y=read(); for (int i = 1; i <= x; ++i) { for (int j = 1; j <= y; ++j) { ans+=sum[i*j]; } } cout << ans <<endl; return 0; }
C
对答案有贡献的边肯定是最大生成树上的边,因为这棵树是所有选出来的树当中权值总和最大的,那么可以将这些边先拉出来,每条边至少会被贡献一次。
对于一条最大的边,我们要让它产生贡献,那么只能是这条边的两个点产生出来,之后这条边再也不会有所贡献了,同理其他的边,因此可以看出每条边只对答案贡献了一次。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} struct node { int u,v,w; bool operator<(node& x) const { return w>x.w; } }; vector<node> G; struct DSU{ int a[maxn],sz[maxn]; void init(int n){ iota(a,a+n+1,0); fill(sz,sz+n+1,1); } int fa(int x){ return a[x]==x?x:a[x]=fa(a[x]); } bool query(int x,int y){ //查找 return fa(x)==fa(y); } void join(int x,int y){ //合并 x=fa(x),y=fa(y); if(x==y)return; if(sz[x]>sz[y])swap(x,y); a[x]=y; sz[y]+=sz[x]; } int operator[](int x){return fa(x);} }d; int n,m,u,v,w; ll ans; int main() { #ifndef ONLINE_JUDGE debug; #endif n=read(),m=read(); d.init(n); for (int i = 1; i <= m; ++i) { u=read(),v=read(),w=read(); G.pb({u,v,w}); } sort(G.begin(),G.end()); for (auto x:G) { if (d.query(x.u,x.v)) continue; ans+=x.w; d.join(x.u,x.v); } cout << ans <<endl; return 0; }
D
一个选手的分数 ai 加 d 会导致区间 (ai,ai+d)中的数必须都要+d
那么一个选手就会牵连致其他选手,构成一个团体
考虑分组背包,当前选手不加d,那么就要看前一位选手会不会牵连到他,当前选手加d,那么前一位选手加不加都无所谓。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 5005; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 998244353; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} struct CC{ static const int N=5005; ll fac[N],inv[N]; CC(){ fac[0]=1; for (int i = 1; i < N; ++i) fac[i]=fac[i-1]*i%mod; inv[N-1]=qpow(fac[N-1],mod-2); for (int i = N-1; i>= 1; --i) inv[i-1]=inv[i]*i%mod; } ll operator()(ll a,ll b){ //a>=b if(a<b || b<0)return 0; return fac[a]*inv[a-b]%mod*inv[b]%mod; } ll A(ll a,ll b){ //a>=b if(a<b || b<0)return 0; return fac[a]*inv[a-b]%mod; } }C; int n; int d,f[maxn][maxn][2],a[maxn]; int main() { #ifndef ONLINE_JUDGE debug; #endif n=read(),d=read(); for (int i = 1; i <= n; ++i) { a[i]=read(); } sort(a+1,a+1+n); f[1][0][0]=f[1][1][1]=1; for (int i = 2; i <= n; ++i) { for (int j = 0; j <= n; ++j) { f[i][j][0]=(f[i][j][0]+f[i-1][j][0])%mod; if(a[i-1]+d<=a[i]) f[i][j][0]=(f[i][j][0]+f[i-1][j][1])%mod; if (j+1 <= n) { f[i][j+1][1]=(f[i][j+1][1]+f[i-1][j][0])%mod; f[i][j+1][1]=(f[i][j+1][1]+f[i-1][j][1])%mod; } } } for (int i = 1; i <= n; ++i) { ll ans = f[n][i][0]+f[n][i][1]; ans %= mod; cout << ans*qpow(C(n,i),mod-2)%mod <<endl; } return 0; }
E
这题再次学到了……
因为要选择一个区间,这个区间的涉及下标和元素要全部一样,所以他们异或起来的值都是一样的,但是为防止下标和元素不同,异或起来的值相同的情况,我们就给予它们一个哈希值,这样就可以完全避免冲突。
#include <bits/stdc++.h> #define debug freopen("r.txt","r",stdin) #define mp make_pair #define ri register int #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double lf; typedef pair<ll, ll> pii; const int maxn = 1e6+10; const int N = 1500+10; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int hash_num = 131; const double eps=1e-6; const double PI=acos(-1.0); inline ll read(){ll s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w;} // mt19937_64 rnd(time(0)); unsigned long long // mt19937 rnd(time(0)); unsigned int mt19937_64 rnd(time(0)); ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;} int n; ll a[maxn],pre[maxn],ans,k[maxn]; unordered_map<ll,int>mapp; int main() { #ifndef ONLINE_JUDGE debug; #endif n=read(); for (int i = 1; i <= n; ++i) { a[i]=read(); k[i]=rnd(); } for (int i = 1; i <= n; ++i) { pre[i] = pre[i-1] ^ k[i] ^ k[a[i]]; } mapp[0]=1; for (int i = 1; i <= n; ++i) { ans+=mapp[pre[i]]; mapp[pre[i]]++; } cout << ans <<endl; return 0; }