B2. Books Exchange (hard version)
题目说,输入的是一个排列,那么每个数(1~n)都会出现,那么每个数都会出现在一个简单环中,bfs处理一下这些点在所在环的数量即可。。
#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
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
vector<int>G[N];
int n,b[N];
int a[N],ans[N];
int tot;
int bfs(int uu,int tot)
{
queue<int>que;
que.push(uu);
int ans=0;
while(que.size()){
int u=que.front();que.pop();
//printf("u:%d\n");
if(b[u]) continue;
b[u]=tot;ans++;
for(int v:G[u]){
//printf("v:%d\n",v);
que.push(v);
}
}
//printf("ans:%d\n",ans);
return ans;
}
int main()
{
int _;cin>>_;while(_--)
{
scanf("%d",&n);
for(int i=1;i<=n;++i) G[i].clear(),b[i]=0;
tot=0;
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
G[i].push_back(a[i]);
}
for(int i=1;i<=n;++i)
{
if(b[i]==0){
tot++;
ans[tot]=bfs(i,tot);
}
}
for(int i=1;i<=n;++i){
printf("%d ",ans[b[i]]);
}
puts("");
}
}
C2. Good Numbers (hard version)
因为是3的某次方相加,那么看作3进制下,每位下就是0或者1,那么我就将输入的x求3进制下的长度,用ans每一位都是1,再高位一个一个减去当前的1,是否大于等于即可
#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
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
const int N=1e4+10;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll cal(ll x)
{
ll t=x;
ll tmp=0;
ll p=0;
while(t){
ll d=x%3;
t=t/3;
tmp+=pow(3ll,p);
++p;
}
tmp+=pow(3ll,p);
//printf("tmp:%lld\n",tmp);
for(ll i=p;i>=0;--i)
{
ll t1=pow(3ll,i);
if(tmp-t1>=x) tmp-=t1;
}
return tmp;
}
int main()
{
int _;cin>>_;while(_--)
{
ll x;
scanf("%lld",&x);
ll ans=cal(x);
printf("%lld\n",ans);
}
}
D2. Too Many Segments (hard version)
每个位置下去掉右端点最远的即可:结合差分弄一下就可以了。。。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,k;
struct node
{
int l,r,id;
bool operator <(const node &o) const
{
return o.r>r;
}
};
vector<node>G[N];
vector<int>ans;
int vis[N];
int main()
{
scanf("%d%d",&n,&k);
int mx=0;
for(int i=1;i<=n;++i)
{
int l,r;
scanf("%d%d",&l,&r);
mx=max(mx,r);
vis[l]++;
vis[r+1]--;
G[l].push_back({l,r,i});
}
int sum=0;
priority_queue<node>que;
for(int i=1;i<=mx;++i)
{
sum+=vis[i];
for(auto v:G[i]) que.push(v);
while(sum>k)
{
node now=que.top();que.pop();
ans.push_back(now.id);
vis[now.r+1]++;
sum--;
}
}
printf("%d\n",ans.size());
for(int v:ans) printf("%d ",v);
}
E. By Elevator or Stairs?
设dp[i][0]为从1开始走楼梯来到i层,dp[i][1]为从1开始做电梯来到i层
显然易见dp方程:
dp[i][0]=min(dp[i-1][0]+a[i],dp[i][0]);
dp[i][0]=min(dp[i-1][1]+a[i],dp[i][0]);
dp[i][1]=min(dp[i-1][0]+c+b[i],dp[i][1]);
dp[i][1]=min(dp[i-1][1]+b[i],dp[i][1]);
#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
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
ll a[N],b[N];
ll dp[N][2];
int main()
{
memset(dp,inf,sizeof(dp));
int n,c;
cin>>n>>c;
for(int i=2;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=2;i<=n;++i){
scanf("%lld",&b[i]);
}
dp[1][0]=0;
dp[1][1]=c;
for(int i=2;i<=n;++i){
dp[i][0]=min(dp[i-1][0]+a[i],dp[i][0]);
dp[i][0]=min(dp[i-1][1]+a[i],dp[i][0]);
dp[i][1]=min(dp[i-1][0]+c+b[i],dp[i][1]);
dp[i][1]=min(dp[i-1][1]+b[i],dp[i][1]);
}
for(int i=1;i<=n;++i) printf("%lld ",min(dp[i][0],dp[i][1]));
}