本次训练赛大量涉及STL。
D题
题意
https://ac.nowcoder.com/acm/contest/3005/D
长度为n数组,求子段异或值为0的个数。
这道题据说是滴滴还是字节跳动面试题改编,原题是不可分割求最大,用DP,这一题是可分割,应该是简单了不少。
思路
与其说思路不如说是教训。
- 数组开太大(2e5*2e5)即使是在全局变量里面开出来也不允许,而且这种情况是段错误而不是MLE。
- wa了也不能证明不会TLE。
- N=2e5就不要幻想n2的复杂度能过了。
我的错误代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=2e5+7;
ll a[N],res[N];
int main() {
int n;
cin>>n>>a[1];
res[1]=a[1];
ll cnt=0;
for(int i=2; i<=n; i++) {
cin>>a[i];
res[i]=res[i-1]^a[i];
if(!res[i]) cnt++;
}
for(int i=2; i<=n; i++) {
for(int j=i; j<=n; j++) {
res[j]=res[j]^res[i-1];
if(!res[j]) cnt++;
}
}
cout<<cnt<<endl;
return 0;
}//通过率60% TLE出题人的正确思路
作者:nocriz https://ac.nowcoder.com/discuss/365889?toCommentId=5266036
如果[l,r]是合法的子段,说明前缀和中xorsum[r]^xorsum[l-1] = 0, xorsum[l-1] = xorsum[r]。
求出异或前缀和,然后使用map计数每一个数字有多少个前缀和等于那个数字即可。
出题人太强了,本菜鸡没看懂,只能自己琢磨一下:
我写了一个生成前缀和xorsum的程序来辅助理解
#include<bits/stdc++.h>
using namespace std;
int main() {
int n,k,y=0;
cin>>n;
int xorsum[10]= {0};
for(int i=1; i<=n; i++)
cin>>k,xorsum[i]=xorsum[i-1]^k,cout<<xorsum[i]<<" ";
}
/* 输入输出:
5
1 2 3 2 1
1 3 0 2 3 */如果[l,r]是合法子段 xorsum[r]^xorsum[l-1] = 0
我明白了,就是我的方案的终极优化版。
正确代码
#include<iostream>
#include<map>
using namespace std;
map<int,int> mp;
int main(){
int n,k,y=0;
cin>>n;
long long sum=0;
mp[0]++;
while(n--){
cin>>k;//不用存的gjr
y^=k;
sum+=mp[y];//前面有多少个相同的前缀和就加多少个
mp[y]++;//本身记录
}
cout<<sum<<endl;
}E题
题意
https://ac.nowcoder.com/acm/contest/3005/E
将字符串中的字符任意排列,但每种字符数目不变,使得结果是一个合法的表达式,而且表达式的值最小。输出结果。
思路
有多少个加号就有多少个区间,把所有的数字放在一起sort,因为不包括0,所以直接从小到大往高位放就是了。
然后就是一个字符串模拟大数加法,可以拿之前的大数类模板来试试手。
等我有空()回来补一下吧。
代码
cpp代码
#include<iostream>
#include<algorithm>
using namespace std;
int tail,head;
int s[500005],c;
int ans[500005],jw=0,pl;
int main() {
while((c=getchar())!='\n') {
if(c=='+')
pl++;
else
s[++tail]=c-'0';
}
pl++;
sort(s,s+tail+1);
for(int i=tail; i>=1; i-=pl) {
int base=0;
for(int j=i; j>=i-pl+1&&j>=1; j--) {
base+=s[j];
}
base+=jw;
ans[++head]=base%10;
jw=base/10;
}
if(jw>0)
ans[++head]=jw;
for(int i=head; i>=1; i--)
printf("%d",ans[i]);
return 0;
}Python代码
s=input()
num=1
List=[0]*10
for i in s:
if i=='+':
num+=1
else:
List[int(i)]+=1
Sum=0
ans=[]
Len=len(s)-num+1
def fun():
global List
for i in range(9,0,-1):
if List[i]>0:
List[i]-=1
return i
else:
return 0
for i in range(Len):
if i%num==0:
ans.append(str(Sum%10))
Sum//=10
Sum+=fun()
print(str(Sum)+''.join(ans[:0:-1]))
# 我还以为可以直接大数处理呢 C题
思路
划分区间,双指针。除法要记得取模!!!
代码
本菜鸡的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=2e5+7;
ll a[N];
int pos[N];
ll qkpow(ll x, ll y) {
ll ans = 1;
x = x % mod;
while (y) {
if(y&1) ans = ans * x % mod;
x = x * x % mod;
y =y >>1;
}
return ans;
}
ll getInv(ll x) {
return qkpow(x,mod-2);
}
int main() {
int n,k,t=1;
cin>>n>>k;
for(int i=1; i<=n; i++) {
cin>>a[i];
if(a[i]==0) pos[t++]=i;
}
int right[N],left[N],as=0,it;
for(it=1; it<t; it++)
if(pos[it]-pos[it-1]>k) right[as]=pos[it]-1,left[as++]=pos[it-1]+1;
//共有0 - as-1 段 区间右端点分别为right
if(n-k>=pos[t-1]) left[as]=pos[t-1]+1,right[as++]=n;
ll ans=0;
for(int j=0; j<as; j++) {
int L=left[j],R=right[j];
//cout<<"L="<<L<<" R="<<R<<endl;
ll tmp=1;
for(int i=L; i<L+k; i++) {
tmp*=a[i];
tmp%=mod;
}
ans=max(ans,tmp);
for(int i=L+k; i<=R; i++) {
tmp=tmp*getInv(a[i-k]);
tmp%=mod;
tmp*=a[i];
tmp%=mod;
ans=max(ans,tmp);
}
}
cout<<ans<<endl;
return 0;
}更加简单干净的表述
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const ll mod=998244353;
ll p[200005];
int n,k;
ll qm(ll x,ll y){
ll ans=1;
while(y){
if(y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
int main(){
cin>>n>>k;
ll ans=0;
ll cnt=1;
int num=0;
for(int i=1;i<=n;i++){
cin>>p[i];
if(p[i]==0){
num=0;
cnt=1;
}
else{
num++;
cnt=cnt*p[i]%mod;
if(num==k){
ans=max(ans,cnt);
cnt=cnt*qm(p[i-k+1],mod-2)%mod;
num--;
}
}
}
cout<<ans;
}Python代码
n,k=map(int,input().split())
a=list(map(int,input().split()))
S=1
num=ans=0
p=998244353
for i in range(n):
if a[i]:
S*=a[i]
num+=1
if num>k:
S*=pow(a[i-k],p-2,p)
num-=1
if num==k:
ans=max(ans,S%p)
else:S=1;num=0
S%=p
print(ans)B题
思路
看了半天都没看出来是栈,想了很久……
代码
我的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
bool chk(string s) {
char stack [s.length()];
int head = 0;
for(int i=0;i<s.length();i++) {
char c=s[i];
switch(c) {
case '{':
case '[':
case '(':
stack[head++] = c;
break;
case '}':
if(head == 0 || stack[--head] != '{') return false;
break;
case ')':
if(head == 0 || stack[--head] != '(') return false;
break;
case ']':
if(head == 0 || stack[--head] != '[') return false;
break;
}
}
return head == 0;
}
int main() {
string s;
cin>>s;
if(chk(s)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}STL
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
int main() {
string s;
cin>>s;
int n=s.length();
stack <char> st;
for(int i=0;i<n;i++){
if(s[i]=='('||s[i]=='['||s[i]=='{') st.push(s[i]);
else if(s[i]==')'&&!st.empty()&&st.top()=='(') st.pop();
else if(s[i]==']'&&!st.empty()&&st.top()=='[') st.pop();
else if(s[i]=='}'&&!st.empty()&&st.top()=='{') st.pop();
else {
cout<<"No"<<endl;
return 0;
}
}
if(st.empty()) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}- st.pop要加非空判断 如果空 会越界 RE
- 对于string s.size()和s.length()都可以
Python
s=input() S=[] for i in s: S.append(i) if len(S)>1 and S[-2:] in(['(',')'],['[',']'],['{','}']): S.pop();S.pop() print('YNeos'[S!=[]::2])stl
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ string s; stack<char>a; cin>>s; for(int i=0;i<s.size();i++){ if(!a.empty()&&((s[i]==')'&&a.top()=='(')||(s[i]==']'&&a.top()=='[')||(s[i]=='}'&&a.top()=='{'))) a.pop(); else a.push(s[i]); } if(!a.empty()) puts("No"); else puts("Yes"); }最后A题错了两次因为没改longlong

京公网安备 11010502036488号