A:先免费跳2,最终情况是都跳在x和x+1的位置。奇偶取min即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
int x,j=0,o=0;
for(int i=1;i<=n;i++)
{
cin>>x;
if(x&1)j++;
else o++;
}
cout<<min(j,o)<<endl;
return 0;
}
B:逆序,判断是否小于前面最小即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e6+7;
int a[M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t,n;
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int mi=1e9,ans=0;
for(int i=n;i>=1;i--)
{
if(a[i]>mi)ans++;
mi=min(a[i],mi);
}
cout<<ans<<endl;
}
return 0;
}
C:
方法一:
只跟末尾有关,循环节最长为10
我直接找循环节,搞搞就行
方法二:
最终的数是:m,2*m,3*m ……11*m,12*m……n/m *m
我们统计下[1,n/m]中末尾1-9出现的次数,
一个末尾i的数的贡献是:(i*m)%10;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int xh[20];
int vs[20];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
memset(vs,0,sizeof(vs));
memset(xh,0,sizeof(xh));
ll n,m;
cin>>n>>m;
ll nm=n/m;//写几次
ll tp=m%10;//末尾为tp
int sz=0;
ll w=0;
ll now=tp;
while(1)
{
if(vs[tp])break;
vs[tp]=1;
xh[++sz]=tp;w+=tp;
tp=(tp+now)%10;
}
ll xhnm=nm/sz;
ll ans=xhnm*w;
for(int i=1;i<=nm%sz;i++)
ans+=xh[i%sz];
cout<<ans<<endl;
}
return 0;
}
D:记录每个数出现的最大次数,和到达这个数用的次数集合。
取次数最小的k次即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;
int a[M];
int ct[M];
multiset<int>s[M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
int tp=a[i],nt=0;
while(tp)
{
ct[tp]++;
s[tp].insert(nt);
nt++;
tp/=2;
}
}
ll mi=1e18;
for(int i=1;i<=200000;i++)
{
if(ct[i]>=k)
{
// cout<<i<<" "<<ct[i]<<endl;
ll ans=0,tp=0;
for(auto x:s[i])
{
// cout<<x<<" ";
ans+=x;
tp++;
if(tp==k)break;
}
// cout<<" --"<<endl;
mi=min(ans,mi);
}
}
cout<<mi<<endl;
return 0;
}
E:
如果s,t 都不是两个字符相同的情况, 我们枚举"abc"的全排列,得到满足条件的串xyz.最后输出 xxxyyyzzz的形式即可,这样出现的子串为:xy,yz,判断下s、t都不为xy,yz就说明这个全排列可行。
如果s,t出现重复字符 例如:s:“aa”,假设找到可以的串,xyz,最后输出xyzxyzxyz的形式。
这种情况子串为:xy,yz,zx 要同时满足s、t都不等于这三个子串 才说明这个全排列可行
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e5+7;
char s1[4],s2[4];
char s[3]={'a','b','c'};
void gao1()
{
do
{
bool f=false;
for(int i=0;i<=1;i++)
{
if(s[i]==s1[0]&&s[i+1]==s1[1])f=true;
if(s[i]==s2[0]&&s[i+1]==s2[1])f=true;
}
if(!f)break;//s1,s2都不是S的子串
}while(next_permutation(s,s+3));
}
void gao2()
{
do
{
bool f=false;
for(int i=0;i<=1;i++)
{
if(s[i]==s1[0]&&s[i+1]==s1[1])f=true;
if(s[i]==s2[0]&&s[i+1]==s2[1])f=true;
}
if(s[2]==s1[0]&&s[0]==s1[1])f=true;
if(s[2]==s2[0]&&s[0]==s2[1])f=true;
if(!f)break;//s1,s2都不是S的子串
}while(next_permutation(s,s+3));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
cin>>s1>>s2;
cout<<"YES"<<endl;
if(s1[0]==s1[1]||s2[0]==s2[1])
{
gao2();
for(int i=1;i<=n;i++)cout<<s;
}
else
{
gao1();
// cout<<s<<endl;
for(int j=0;j<=2;j++)
for(int i=1;i<=n;i++)cout<<s[j];
}
return 0;
}
G:
如果是单次询问的话非常简单:
删去边权>=q的边,然后得到一颗颗子树,对每颗子树求任意满足u<v 点对u,v的个数 (其实就是联通块大小sz,sz*(sz-1)/2)
但这题是多次。
由于是问路径上最大值,我们不妨从边权最小的开始加入,
假设加入到边权为wi的边,此时qi<w的所有情况都已经确定,因为其他边都是大于等于w的。
对于这条边,会给所有qi>=w 的情况 带来 siz[gu]*sz[gv]个点对的贡献。
上述操作用差分处理下即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;
struct node{
int u,v,w;
}ee[M];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int fa[M];
ll siz[M];
int get(int x)
{
if(fa[x]==x)return fa[x];
return fa[x]=get(fa[x]);
}
ll ans[M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,q,u,v,w;
cin>>n>>q;
for(int i=1;i<=n-1;i++)
cin>>ee[i].u>>ee[i].v>>ee[i].w,fa[i]=i,siz[i]=1;
fa[n]=n,siz[n]=1;
sort(ee+1,ee+n,cmp);//按边权从大到小
for(int i=1;i<n;i++)
{
u=ee[i].u,v=ee[i].v,w=ee[i].w;
int gu=get(u),gv=get(v);
// cout<<u<<" "<<v<<" "<<w<<" ="<<siz[gu]<<" "<<siz[gv]<<endl;
ans[w]+=siz[gu]*siz[gv];
fa[gu]=gv;
siz[gv]+=siz[gu];
}
for(int i=1;i<=200000;i++)ans[i]+=ans[i-1];
while(q--)
{
int x;
cin>>x;
cout<<ans[x]<<" ";
}
return 0;
}