目录
A. Tanya and Stairways
B. Delete from the Left
C. Summarize to the Power of Two
D. Polycarp and Div 3
E. Median on Segments
F. Berland and the Shortest Paths
A. Tanya and Stairways
简单性质题
我们找到性质,如果这个数大于等于后面的数就是到结尾了,特例就是i==n
void solve(){
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<int> res;
for(int i=1;i<=n;i++){
if(a[i]>=a[i+1] || i==n){
res.push_back(a[i]);
}
}
cout<<res.size()<<endl;
for(auto&v:res) cout<<v<<' ';
cout<<endl;
return ;
}
B. Delete from the Left
简单性质
按照题目意思是从左边开始删除直到后面的全都相等为止,所以我们可以考虑直接倒着来直到不想等就是需要删除到的位置,如果一个都跑完了还没有结果,答案就是长的砍掉多的一节
void solve(){
string a,b; cin>>a>>b;
n=a.size(),m=b.size();
a=' '+a,b=' '+b;
for(int i=n,j=m;i>=1&& j>=1;i--,j--){
if(a[i]!=b[j]){
cout<<i+j<<endl;
return ;
}
}
cout<<max(n,m)-min(n,m)<<endl;
return ;
}
C. Summarize to the Power of Two
题目是判断是否是存在2的幂次,可以简单得到对于x如果y是对应数,那么对于y,x也是他的对应数
所以可以把所有的数都加入其中然后判断他是否有满足的对应数(同时特判同一种数且数量为1)
void solve(){
cin>>n;
map<LL,int> mp;
for(int i=1;i<=n;i++){
LL x; cin>>x;
mp[x]++;
}
int ans=0;
for(auto&[v,w]:mp){
bool ok=false;
for(int j=1;j<=32;j++){
LL x=1ll<<j;
if(x<=v) continue;
if(mp.count(x-v)){
if(x-v==v && w==1) continue;
else ok=true;
}
}
ans+= !ok ? w : 0;
}
cout<<ans<<endl;
return ;
}
D. Polycarp and Div 3
对数切割使其变成最多3的倍数,我们明显发现如果是3的倍数直接切割就行,如果从前到后判断是不是出现了3的倍数呢?只要是前面出现的余数此时又出现就是或者说当前余数变为了0那也是,由此可以推广为任意的数的倍数的公式
void solve(){
string s;
map<int,int> mp;
cin>>s;
int ans=0,m=3,res=0;
for(auto&v:s){
ans=ans+(v-'0');
ans%=3;
if(mp.count(ans) || !ans){
res++;
ans=0;
mp.clear();
}
else mp[ans]++;
}
cout<<res<<endl;
return ;
}
E. Median on Segments
我们对于求解满足要求的区间数量首先分析,要求是恰好中位数是m的区间数,如果直接求解这样的区间数量是难以解决的,但是我们利用前缀和的思维我们可以简单求解出中位数大于等于m的区间个数,[l,r]对于这个区间只要即可求解出符合的区间要求对于前缀和维护同时求解方案数可以使用树状数组来求解,对于题目要求转化为
中位数>=m的区间数-中位数>=m+1的区间数,同属对于这个问题的求解如上
struct BIT{
int tr[N];
void add(int k,int x){
for(int i=k;i<=2*n;i+=lowbit(i)) tr[i]+=x;
}
int query(int k){
int res=0;
for(int i=k;i;i-=lowbit(i)) res+=tr[i];
return res;
}
int ask(int l,int r){// 先左再右
return query(r)-query(l-1);
}
void clear(){
for(int i=0;i<=2*n+2;i++) tr[i]=0;
}
}tree;
int work(int x){
tree.clear();
vector<int> c1(n+1),c2(n+1);
int ans = 0;
tree.add(n+1,1);// 表示 0的位置
for(int i=1;i<=n;i++){
c1[i]=c1[i-1],c2[i]=c2[i-1];
if(a[i]>=x) c1[i]++;
else c2[i]++;
ans+=tree.query(c1[i]-c2[i]+n); // 表示查询小于等于差值的位置
tree.add(c1[i]-c2[i]+n+1,1);
}
return ans;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
work(m);
cout<<work(m)-work(m+1)<<endl;
// 我要求的是以m为中位数的方案的数量
// 等价于以>=m为中位数的方案 - >=m+1 为中位数的方案
return ;
}
F. Berland and the Shortest Paths
最短路径树,我们可以直接按照dijkstra的方式求解即可因为我们要的是根节点到其他的点的路径的最小值,所以不同于最小生成树,同时考虑存起来每一个点的前驱节点
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
vector<int> pre[N];
void solve()
{
memset(h,-1,sizeof h);
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
int a,b; cin>>a>>b;
add(a,b);
add(b,a);
}
auto bfs = [&](){
memset(d,0x3f,sizeof d);
queue<int> q;
q.push(1); d[1]=0;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(d[j]>d[u]+1){
d[j]=d[u]+1;
pre[j].push_back((i+1)/2);
q.push(j);
}
else if(d[j]==d[u]+1){
pre[j].push_back((i+1)/2);
}
}
}
};
bfs();
int ans=1;
for(int i=2;i<=n;i++){
ans*=pre[i].size();
if(ans>k){
ans=k;
break;
}
}
cout<<ans<<endl;
vector<int> vis(m+1,0);
function<void(int)> dfs = [&](int x){
if(x==n+1){
for(int i=1;i<=m;i++){
cout<<vis[i];
}
cout<<endl;
ans--;
if(!ans) exit(0);
return ;
}
for(auto&v:pre[x]){
vis[v]=1;
dfs(x+1);
vis[v]=0;
}
return ;
};
dfs(2);
return ;
}