D2 Equalizing by Division (hard version)
將每個數從除2除2移動中,保存能到達的地方的步數。然後暴力枚舉i,i數能否有k個數相同。水題一個,但是我思路不是這個,是另一種優先隊列的做法,無奈一直wa8.
每個數提供的數最多是log(1e5)個,所有的之和是n*log(1e5),每個數遍歷一次,所以不會超時
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],vis[N];
multiset<int> st[N];
void cal(int x)
{
int cnt=0;
while(x)
{
st[x].insert(cnt++);
x/=2;
}
st[0].insert(cnt);
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;++i)
{
int x;
cin>>x;
cal(x);
}
int ans=0x3f3f3f3f;
for(int i=200000;i>=0;--i)
{
if(st[i].size()>=k)
{
int tmp=0;
int num=1;
for(auto it=st[i].begin();it!=st[i].end()&&num<=k;it++)
{
num++;
tmp+=*it;
}
ans=min(ans,tmp);
}
}
printf("%d\n",ans);
}
題意:給定一個整數n和兩個長度爲2的字符,只包含a,b,c。構造一個字符串包含n個a,n個b,n個c。
極其複雜的構造,具體詳情看代碼吧
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
char a[3],b[3];
int main()
{
int n;
cin>>n;
cin>>a>>b;
puts("YES");
int t='a'+'b'+'c';
if(a[0]==a[1]&&b[0]==b[1]&&a[0]==b[0])
{
if(a[0]=='A') rep(i,1,n) {
printf("b");
printf("a");
printf("c");
}
else if(a[0]=='B')rep(i,1,n) {
printf("c");
printf("b");
printf("a");
}
else rep(i,1,n) {
printf("b");
printf("c");
printf("a");
}
return 0;
}
if(a[0]==a[1]&&b[0]==b[1])
{
rep(i,1,n)
{
printf("%c",a[0]);
printf("%c",t-a[0]-b[0]);
printf("%c",b[0]);
}
return 0;
}
if(a[0]==b[1]&&a[1]==b[0])
{
//printf("***\n");
rep(i,1,n) printf("%c",a[1]);
rep(i,1,n) printf("%c",t-a[1]-a[0]);
rep(i,1,n) printf("%c",a[0]);
return 0;
}
if(a[0]==a[1])
{
rep(i,1,n){
printf("%c",b[1]);
printf("%c",b[0]);
printf("%c",t-b[1]-b[0]);
}
return 0;
}
if(b[0]==b[1])
{
rep(i,1,n) {
printf("%c",a[1]);
printf("%c",a[0]);
printf("%c",t-a[1]-a[0]);
}
return 0;
}
if(a[0]==b[0])
{
rep(i,1,n) printf("%c",b[1]);
rep(i,1,n) printf("%c",t-b[1]-b[0]);
rep(i,1,n) printf("%c",b[0]);
return 0;
}
if(a[0]==b[1])
{
rep(i,1,n) printf("%c",a[1]);
rep(i,1,n) printf("%c",a[0]);
rep(i,1,n) printf("%c",b[0]);
return 0;
}
if(a[1]==b[0])
{
rep(i,1,n) printf("%c",b[1]);
rep(i,1,n) printf("%c",b[0]);
rep(i,1,n) printf("%c",a[0]);
return 0;
}
if(a[1]==b[1])
{
rep(i,1,n) printf("%c",b[1]);
rep(i,1,n) printf("%c",a[0]);
rep(i,1,n) printf("%c",b[0]);
return 0;
}
}
F. Unstable String Sort
題解學習來自:https://blog.csdn.net/liufengwei1/article/details/100168302
很秀的做法。我的tarjan還是不能脫板,要看板子,然後有個地方沒有打好,一直在wa,也沒有懷疑板子問題。
唉,還是要儘量理解。
具體做法:tarjan縮點+拓撲排序
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e5+10;
vector<int>G[N],g[N];
int dfn[N],low[N],in[N],scc[N],a[N],b[N],ans[N];
int fa[N];
int n,k,index,sccnum;
stack<int>que;
int id;
void tarjan(int root)
{
dfn[root]=low[root]=++index;
que.push(root);
for(int v:G[root])
{
if(!dfn[v])
{
tarjan(v);
low[root]=min(low[root],low[v]);
}
else if(!scc[v]) low[root]=min(low[root],dfn[v]);
}
if(low[root]==dfn[root])
{
sccnum++;
int x;
do{
x=que.top();que.pop();
scc[x]=sccnum;
}while(x!=root);
}
}
void topo()
{
queue<int>que;
for(int i=1;i<=sccnum;++i) if(in[i]==0) que.push(i);
id=0;
while(que.size())
{
int x=que.front();que.pop();
if(id<26)id++;
b[x]=id-1;
for(int v:g[x])
{
in[v]--;
if(in[v]==0) que.push(v);
}
}
}
int main()
{
cin>>n>>k;
rep(i,1,n) cin>>a[i];
for(int i=1;i<n;++i) G[a[i]].push_back(a[i+1]);
rep(i,1,n) cin>>a[i];
for(int i=1;i<n;++i) G[a[i]].push_back(a[i+1]);
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;++i)
{
for(int v:G[i])
{
//if(scc[i]!=scc[v]&&fa[scc[v]]!=scc[i])
if(scc[i]!=scc[v])
{
fa[scc[v]]=scc[i];
g[scc[i]].pb(scc[v]);
in[scc[v]]++;
}
}
}
topo();
if(id<k)
{
puts("NO");
return 0;
}
for(int i=1;i<=n;++i) ans[i]=b[scc[i]];
puts("YES");
for(int i=1;i<=n;++i) printf("%c",ans[i]+'a');
}
/*
3 1
1 3 2
3 2 1
*/
並查集維護答案。
題意:給一個樹,每條邊有邊權,m次詢問。
每次詢問給定一個x,問樹上路徑(u,v)最大值的數小於等於x。
這題初步看好像很難,其實就是有點難。
做法:從小枚舉邊權,計算當前邊權w的答案,答案就這條邊兩端的連通塊相乘,siz[u]*siz[v]。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n,m;
vector<int>g1[N],g2[N];
int siz[N];
int fa[N];
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
ll ans[N];
ll meger(int x1,int y1)
{
int x=find(x1);
int y=find(y1);
ll res=0;
if(x!=y)
{
fa[x]=y;
res=1ll*siz[x]*siz[y];
siz[y]+=siz[x];
}
return res;
}
int main()
{
cin>>n>>m;
for(int i=1;i<n;++i)
{
int u,v,w;
cin>>u>>v>>w;
g1[w].pb(u);
g2[w].pb(v);
}
for(int i=1;i<=n;++i) siz[i]=1,fa[i]=i;
for(int i=1;i<=200000;++i)
{
ans[i]=ans[i-1];
for(int j=0;j<g1[i].size();++j)
ans[i]+=meger(g1[i][j],g2[i][j]);
}
while(m--)
{
int q;
cin>>q;
printf("%lld ",ans[q]);
}
return 0;
}