A
枚举m到2e5为因数,期间更新最大公因数。
int n, m; cin>>n>>m;
vector<pair<int,int>> ans;
unordered_map<int,int> mp;
for(int i=0;i<n;i++){
int x; cin>>x;
mp[x]++;
}
for(int i=m;i<=2e5;i++){
int sum=0, num=0;
for(int j=i;j<=2e5;j+=i){
if(mp.count(j)){
sum+=mp[j];
num=__gcd(num,j);
}
}
if(sum>1){
ans.emplace_back(sum,num);
}
}
sort(ans.begin(),ans.end(),[&](auto p1, auto p2){
if(p1.first==p2.first) return p1.second<p2.second;
return p1.first>p2.first;
});
if(ans.size()){
cout<<ans[0].first<<" "<<ans[0].second<<"\n";
} else cout<<"0 0\n";
B
手推一下,枚举最终答案,要想x成立,b数组中不能有x,则原数组中的子数组中,x要被夹在1,2,,,x-1中,例:x=4, 则子数组 1,4,3,2 成立,而4,2,1,3就不成立。
int n; cin>>n;
vector<int> v(n), ind(n);
for(int i=0;i<n;i++){
cin>>v[i]; v[i]--;
ind[v[i]]=i;
}
if(n==1){
cout<<"1\n";
return 0;
}
int l=ind[0], r=ind[1];
if(l>r) swap(l,r);
for(int i=2;i<n;i++){
if(ind[i]>l&&ind[i]<r){
cout<<i+1<<"\n";
return 0;
}
l=min(l,ind[i]);
r=max(r,ind[i]);
}
cout<<n+2<<"\n";
C
int T, H, t, n; cin>>T>>H>>t>>n;
if(H*t>=T*n) cout<<"kirito\n";
else cout<<"hangeki\n";
D
从终点开始倒着循环,注意方向。
int n, m; cin>>n>>m;
vector<vector<int>> v(n,vector<int>(m)), ans(n,vector<int>(m,-1)), dir={{0,-1},{-1,0},{0,1},{1,0}};
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
char c; cin>>c;
if(c=='L') v[i][j]=0;
else if(c=='R') v[i][j]=2;
else if(c=='U') v[i][j]=1;
else v[i][j]=3;
}
}
int a=n-1, b=m-1, c=0;
while(1){
ans[a][b]=c;
int x=a+dir[(v[a][b]+2)%4][0], y=b+dir[(v[a][b]+2)%4][1];
if(x<0||x>=n||y<0||y>=m) break;
if(ans[x][y]!=-1) break;
a=x, b=y, c+=1;
}
for(auto& it:ans){
for(auto& _it:it){
cout<<_it<<' ';
}
cout<<'\n';
}
E
待补
F
加分就打,不加分就不打。
int x, n; cin>>x>>n;
vector<int> v(n);
for(int i=0;i<n;i++) cin>>v[i];
for(int i=0;i<n;i++){
if(v[i]>x){
x+=(v[i]-x)/2;
}
}
cout<<x<<"\n";
G
待补
H
一开始还以为二分加01背包呢,复杂度太爆炸了。只是一个单纯的二分从小到大拿。
int n, s; cin>>n>>s;
vector<int> v(n), ans(n+1);
for(int i=0;i<n;i++) cin>>v[i];
auto check=[&](int k){
vector<int> _v=v;
for(int i=0;i<n;i++) _v[i]+=k*(i+1);
sort(_v.begin(),_v.end());
int sum=0;
for(int i=0;i<k;i++){
sum+=_v[i];
if(sum>s){
return 0;
}
}
ans[k]=sum;
return 1;
};
int l=0, r=n+1, mid;
while(l+1<r){
mid=(l+r)>>1;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l<<" "<<ans[l]<<"\n";
I
具体没有证明,手推了一下,例如:x=7,先拿1,后拿6;先拿2,后那5;先拿3,后拿4。所以只要先手拿不完,后手必赢。
int n; cin>>n;
if(n==1) cout<<"Dbqjubmjtn\n";
else cout<<"Tpdjbmjtn\n";
J
假做法: 每一位存下后面最近的大于自身和小于自身的下标。每次确定最区间,右区间跳跃过最大值和最小值相同的个数。例如:5 2 4 3 1。一开始l=0, r=1,跳过中间2,3,直接跳到最小值发生变化的4。
后面理解了仔细点挺好写的。主要是前面后面最近的大于自身和小于自身的下标不好找,开始卡了好久,又来想到用set(其实priority_queue也可以)。对小于自身的数组:从大往小更新过去未更新的数。同理,对大于自身的数组:从小往大更新过去未更新的数。
这种做法的最坏时间复杂度是n*n,但是可以过,这道题可能数据有点弱。例如:1,2,3,4,5.
真做法还不会。
int n; cin>>n;
set<int> sti, sta;
vector<int> v(n), ind(n), mi(n,n), ma(n,n);
for(int i=0;i<n;i++){
cin>>v[i];
v[i]--;
ind[v[i]]=i;
}
if(n==1){
cout<<0<<"\n";
return 0;
}
for(int i=0;i<n;i++){
while(sti.size()){
int x=*sti.rbegin();
if(x>v[i]){
mi[ind[x]]=i;
sti.erase(x);
} else break;
}
while(sta.size()){
int x=*sta.begin();
if(x<v[i]){
ma[ind[x]]=i;
sta.erase(x);
} else break;
}
sti.insert(v[i]);
sta.insert(v[i]);
}
int ans=0, mod=998244353;
for(int i=0;i+1<n;i++){
int idmi=i, idma=i+1;
if(v[idmi]>v[idma]) swap(idmi,idma);
ans=(ans+mod+idma-idmi)%mod;
while(1){
if(mi[idmi]<ma[idma]){
ans=(ans+mod+(mi[idmi]-max(idma,idmi)-1)*(idma-idmi))%mod;
idmi=mi[idmi];
ans=(ans+mod+idma-idmi)%mod;
} else if(mi[idmi]>ma[idma]){
ans=(ans+mod+(ma[idma]-max(idma,idmi)-1)*(idma-idmi))%mod;
idma=ma[idma];
ans=(ans+mod+idma-idmi)%mod;
} else{
ans=(ans+mod+(n-max(idma,idmi)-1)*(idma-idmi))%mod;
break;
}
}
}
cout<<ans<<"\n";
K
和J题一样的思路,一个大减小,一个绝对值,都是假做法。 按理说两题基本上一模一样,为啥k只有4个人过?
int n; cin>>n;
set<int> sti, sta;
vector<int> v(n), ind(n), mi(n,n), ma(n,n);
for(int i=0;i<n;i++){
cin>>v[i];
v[i]--;
ind[v[i]]=i;
}
if(n==1){
cout<<0<<"\n";
return 0;
}
for(int i=0;i<n;i++){
while(sti.size()){
int x=*sti.rbegin();
if(x>v[i]){
mi[ind[x]]=i;
sti.erase(x);
} else break;
}
while(sta.size()){
int x=*sta.begin();
if(x<v[i]){
ma[ind[x]]=i;
sta.erase(x);
} else break;
}
sti.insert(v[i]);
sta.insert(v[i]);
}
int ans=0, mod=998244353;
for(int i=0;i+1<n;i++){
int idmi=i, idma=i+1;
if(v[idmi]>v[idma]) swap(idmi,idma);
ans=(ans+mod+abs(idma-idmi))%mod;
while(1){
if(mi[idmi]<ma[idma]){
ans=(ans+mod+(mi[idmi]-max(idma,idmi)-1)*abs(idma-idmi))%mod;
idmi=mi[idmi];
ans=(ans+mod+abs(idma-idmi))%mod;
} else if(mi[idmi]>ma[idma]){
ans=(ans+mod+(ma[idma]-max(idma,idmi)-1)*abs(idma-idmi))%mod;
idma=ma[idma];
ans=(ans+mod+abs(idma-idmi))%mod;
} else{
ans=(ans+mod+(n-max(idma,idmi)-1)*abs(idma-idmi))%mod;
break;
}
}
}
cout<<ans<<"\n";
L
每个h存下后面距离最近的a和n,同理,每个t存下后面距离最近的e和n。遍历到每个h和t就尝试删掉。
int n; cin>>n;
string s; cin>>s;
vector<int> v(n,n);
int _n=n, _a=n, _e=n;
for(int i=n-1;i>=0;i--){
if(s[i]=='n') _n=i;
else if(s[i]=='a'){
_a=i;
v[i]=_n;
} else if(s[i]=='e'){
_e=i;
v[i]=_n;
} else if(s[i]=='h'){
v[i]=_a;
} else if(s[i]=='t'){
v[i]=_e;
}
}
int ans=n;
for(int i=0;i<n;i++){
if(v[i]!=n&&v[v[i]]!=n){
if(s[i]=='h'||s[i]=='t'){
ans=min(ans,v[v[i]]-i-2);
}
}
}
cout<<(ans==n?-1:ans)<<"\n";
M
要不去查查自己学校校训?
cout<<"我不知道\n";
`