目录
A. Extract Numbers
B. Queries about less or equal elements
C. Make Palindrome
E. Lomsat gelral
题意:太多不想翻译
思路:字符串模拟,我们使用一个临时变量t去储存每个符号直接的字符串,同时需要注意的是,我们对于空字符串也进行处理,然后在输出的时候判断一下即可。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
const int maxv = 4e6 + 5;
typedef pair pll;
bool check(string s)//检查子段是否合法
{
for(int i=0;i'9') return false;
}
return true;
}
void solve()
{
string s;
cin>>s;
s+=";";
vector c1,c2;
string t;//储存每个符号之间的字符串
for(int i=0;i> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
题意:给你两个整数数组 a和 b。对于第二个数组 bj中的每个元素,你应该找出数组 a中小于或等于数值 bj的元素个数
思路:大水题,Lower bound即可。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
const int maxv = 4e6 + 5;
typedef pair pll;
void solve()
{
int n,m;
cin>>n>>m;
vector a(n),b(m);
for(int i=0;i>a[i];
for(int i=0;i>b[i];
sort(a.begin(),a.end());
for(int i=0;i=0){
cout<> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
题意:给定一个字符串,你可以将其中任意一个字符替换,代价为1,或是对其进行排列,代价为0,令其变为回文串的代价最小且输出字典序最小的回文串
思路:贪心,用一个桶去统计每个字符的出现次数,我们让每个字符的出现次数为偶数,且让这种情况的代价最小。对字符串按长度为奇偶进行讨论:
1,奇数:这个时候,有一个字符串的出现次数为奇数,因为所有字符的出现次数非奇即偶,所以我们对于所有出现次数为奇数的字符,对其次数减一,并将其放入一个vector中进行存储,最后我们一定可以得到一个长度为奇数的vector,此时的最优解为将其右半部分变为左半部分即可,例如:abcde,我们将其变为abcba,这样我们就只修改了d和e这两个字符,这样的花费一定最小。最后再将vector中的字符添加回桶中。
2,偶数:这个时候,只需要将为奇数的字符放入vector中然后进行变换即可。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
const int maxv = 4e6 + 5;
typedef pair pll;
void solve()
{
string s;
cin>>s;
map mp;
for(int i=0;i res;
for(auto [x,y]: mp){
if(y%2){
mp[x]--;
res.push_back(x);
}
}
for(int i=0;i z(sz);
z[sz/2]=res[res.size()/2];//长度为奇数的情况,最中间的字符直接赋值
for(auto [x,y]: mp){//map的key本身有序,所以能直接构造
if(y>0){
y/=2;
for(;y>0;y--){
z[i]=z[sz-i-1]=x;
i++;
}
}
}
for(auto x: z) cout< res;
for(auto [x,y]: mp){
if(y%2){
mp[x]--;
res.push_back(x);
}
}
for(int i=0;i z(sz);
for(auto [x,y]: mp){
if(y>0){
y/=2;
for(;y>0;y--){
z[i]=z[sz-i-1]=x;
i++;
}
}
}
for(auto x: z) cout<> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
题意:给定一颗树,求每个子树中颜色出现次数最多的颜色编号之和。
思路:裸的树上启发式合并。
树上启发式合并:可以高效的用于统计子树信息(不带修改的那种),时间复杂度为nlogn,极为优秀。
基本操作:两遍dfs:
第一遍dfs处理所有节点的相关信息,dfs序,轻儿子和重儿子等。
第二边dfs:
1,先处理所有轻儿子节点,计算但不保留其对于答案的贡献
2,处理所有重儿子节点,保留其对答案的贡献
3,将轻儿子合并进重儿子,计算其对于答案的贡献
#include
using namespace std;
const int N=1e5+5;
typedef long long ll ;
const int maxv=4e6+5;
typedef pair pll;
int l[N],r[N],id[N],sz[N],hs[N],tot;
vector e[N];
int c[N],cnt[N];
ll maxcnt,sumcnt;
ll ans[N];
void dfs1(int u,int f)
{
l[u]=++tot;
id[tot]=u;
sz[u]=1;
hs[u]=-1;
for(auto v: e[u]){
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[v]>sz[hs[u]]) hs[u]=v;
}
r[u]=tot;
}
void add(int x)
{
x=c[x];
cnt[x]++;
if(cnt[x]>maxcnt) maxcnt=cnt[x],sumcnt=0;
if(cnt[x]==maxcnt) sumcnt+=x;
}
void del(int x)
{
x=c[x];
cnt[x]--;
}
void dfs2(int u,int f,bool keep)
{
for(auto v: e[u]) {
if(v!=f&&v!=hs[u]) dfs2(v,u,false);
}
if(hs[u]!=-1) dfs2(hs[u],u,true);
for(auto v: e[u]){
if(v!=f&&v!=hs[u]){
for(int x=l[v];x<=r[v];x++ ) add(id[x]);
}
}
add(u);
ans[u]=sumcnt;
if(!keep){
for(int x=l[u];x<=r[u];x++) del(id[x]);
sumcnt=0,maxcnt=0;
}
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>c[i];
}
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0,false);
for(int i=1;i<=n;i++){
cout<>t;
while(t--){
solve();
}
system("pause");
return 0;
}