SuntoryProgrammingContest2023(AtCoder Beginner Contest 321) - AtCoder
感觉c比d难一些,e比f难一些(
C - 321-like Searcher (atcoder.jp)
分析:纯纯暴力(1~9876543210)肯定不行,我们可以爆搜预处理出所有的合法数字,然后排序,在查询时直接输出
#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
using namespace std;
#define int long long
const int N = 1000010;
int a[N];
vector<int>v;
void dfs(int last,int u,int mx){
if(u==mx+1){
int sum=0;
for(int i=u-1,j=1;i>=0;i--,j*=10){
sum+=a[i]*j;
}
v.push_back(sum);
return;
}
for(int i=0;i<last;i++){
a[u]=i;
dfs(i,u+1,mx);
}
}
signed main(){
int n,x,k;
int sum=0;
cin>>k;
for(int i=0;i<=10;i++){
dfs(10,0,i);
}
sort(v.begin(),v.end());
//cout<<v.size()<<endl;
cout<<v[k]<<endl;
}
分析:每个ai匹配一个bi,暴力是2e5*2e5,显然不行,我们考虑二分,将b数组排序,求一个b数组的前缀和,然后循环a数组,二分出第一个比p-a[i]大的位置,该位置之前的元素,与a[i]之和都是小于p的所以加上a[i]*sum[r-1]就行,该位置到m之间的元素,与a[i]之和都是大于p的所以加上p*(m-r+1)就行
最终答案是
#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
using namespace std;
#define int long long
const int N = 2000010;
int a[N],b[N];
int sum2[N];
signed main(){
int sum=0;
int n,m,p;
cin>>n>>m>>p;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
//sort(a+1,a+1+n);
sort(b+1,b+1+m);
for(int i=1;i<=m;i++) sum2[i]=sum2[i-1]+b[i];
int ans=0;
for(int i=1;i<=n;i++){
int l=1,r=m+1;
while(l<r){
int mid =l+r>>1;
if(b[mid]<=p-a[i]){
l=mid+1;
}else{
r=mid;
}
}
int res=sum2[r-1]+(r-1)*a[i];
int tmp=(m-r+1)*p;
ans+=res+tmp;
}
cout<<ans<<endl;
}
E - Complete Binary Tree (atcoder.jp)
分析:数据量很大,查询次数很多,如何快速地求出答案?
仔细观察我们发现距离和树的深度相关
情况1:节点在查询节点的下方,这时距离就是深度之差
情况2:节点是祖先节点或者是祖先节点的另一侧子节点
如何快速求出个数?
对于情况1我我们只需要 设置两个变量一个mn=now 一个mx=now,每次向下mn*=2,mx=mx*2+1,
直到到达查询节点下面第k层,或是无法继续进行,这时贡献是min(mx,n)-mn+1
对于情况2,我们每次将查询节点的编号/2,得到祖先节点,需要注意,祖先节点向下扩大范围时,会包含住之前已经前一个的祖先节点(或者原查询节点)这时的当前答案,就需要再减去,前一个祖先节点下的k-1次扩大的结果,因为是简单路径(不重复) ,所以不应该包括前一个节点下的k-1次扩大的结果,而且前一个节点的k+1次贡献已经统计,所以直接减去即可
#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
using namespace std;
#define int long long
const int N = 2000010;
int a[N],b[N];
int n;
int sum=0;
int get(int x,int kk){
if(kk<0){
return 0;
}
int mn=x,mx=x;
for(int i=0;i<kk;i++){
mn<<=1;
mx=mx<<1|1;
if(mn>n) return 0;
}
return min(mx,n)-mn+1;
}
void solve(){
int k,x;
cin>>n>>x>>k;
if(!k) {
cout<<1<<endl;
return ;
}
sum=get(x,k);
while(x/2){
k--;
sum+=get(x/2,k)-get(x,k-1);
x/=2;
}
cout<<sum<<endl;
}
signed main(){
int t=1;
cin>>t;
while(t--){
solve();
}
}
F - #(subset sum = K) with Add and Erase (atcoder.jp)
非常快乐的dp
正反背包结束了
#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
using namespace std;
#define int long long
const int N = 2000010,mod=998244353;
int a[N],b[N];
int n;
int sum=0;
int dp[N];
void solve(){
int q,k;
cin>>q>>k;
dp[0]=1;
while(q--){
string op;
int val;
cin>>op>>val;
if(op=="+"){
for(int i=k;i>=val;i--){
dp[i]=(dp[i]+dp[i-val])%mod;
}
}else{
for(int i=val;i<=k;i++){
dp[i]=((dp[i]-dp[i-val])%mod+mod)%mod;
}
}
cout<<dp[k]<<endl;
}
}
signed main(){
int t=1;
//cin>>t;
while(t--){
solve();
}
}