n<=1e5,问将序列变为从小到的顺序的最小操作次数,并输出方案.
显然每个元素只要移动一次,若同一个元素有多次移动,则用其最后一次移动 造成的效果是相同的.
每个元素要么不移动要么移动一次, 求 最少需要操作元素 -> 求最多不需要操作的元素有多少个?
假如不需要移动的元素集合S 则S显然为连续的一段数,否则需要移动.
设dp[a[i]]为以a[i]结尾的最长的一段连续序列,dp[a[i]]=dp[a[i]-1]+1. a[i]-1在a[i]之后则dp[a[i]为1.
找到元素个数最多的S之后,mx=max(S),mn=min(S) 则只要把mx+1,mx+2..n移动最后,把mn-1,mn-2...1.移动到前面即可得到方案.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
int n,a[N],dp[N];
int main()
{
int res=0,l,r;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
dp[a[i]]=dp[a[i]-1]+1;
if(res<dp[a[i]])
res=dp[a[i]],r=a[i];
}
l=r-res+1;
cout<<n-res<<endl;
for(int i=l-1;i>=1;i--)
printf("%d 0\n",i);
for(int i=r+1;i<=n;i++)
printf("%d 1\n",i);
return 0;
}
Problem D
题意:给出n个数,问选k个数,and运算最大能为多少?
n,k<=1e5,a[i]<=1e9.
高位能为1尽量为1,bit位从高到低,采用淘汰法.
若bit位为1的>=k个 则这些数为待选 其余的数肯定不能选 淘汰掉即可.
若待选元素中bit位为1的<k个,则该位只能为0.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
int n,k,a[N],vis[N];
int main()
{
ll ans=0;
cin>>n>>k;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=31;i>=0;i--)
{
int cnt=0;
for(int j=1;j<=n;j++)
{
if(vis[j]) continue;
if((a[j]>>i)&1)
cnt++;
}
if(cnt>=k)
{
ans+=(1ll<<i);
for(int j=1;j<=n;j++)
{
if((((a[j]>>i)&1))==0)
vis[j]=1;
}
}
}
cout<<ans<<endl;
return 0;
}
Problem E
题意:n点m条边的有向无环图(DAG),图中总共有k点能量.
给出初始k个能量的分布位置(同一个结点上可以有多个能量)
现在A,B两人轮流操作,每轮将所有的能量移动到其能到达下一个结点(若有多个结点选择,选最优的).
n,m,k<=1e5,当某人不能操作时算输,问A先手是否必胜?
先考虑简单的情况,只有一个石子,为每个结点定义状态n/p 表示石头在这个结点开始时,先手是必败还是必胜?
所以当某个结点出去结点都为必胜时,该结点为必败.
存在出的的某个结点为必败时 该结点为必胜.
现在有多个石子.若此时所有石子为所在结点都为必胜或者必败 游戏就可以结束了
但是存在有些为必胜 有些为必败 此时应该如何解决?
Alice此时先手 对于状态为必胜的石子 Alice总是有机会移动,对于状态为必败的石子,Alice会先于BoB无法移动的.BOB对必败必胜的石子也是如此.
则最优的策略就是 Alice尽早结束它必胜的石子,也就是让BoB尽早出现无法移动的局面,然后尽量延迟必败石子的移动次数 让自己活的更久.
dp[i]为i开始移动石头的次数,对于结点i
若i为必胜态,则先手的要让它尽快结束,移动到dp[v]最小的一个必败态上.
若i为必败态,则要拖延时间 移动到dp[v]最大的一个v上即可.
总共的轮数取决于:所有初始有石头结点开始移动的次数的最小值.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
int n,c[N],dp[N],ans;
vector<int> e[N];
int f(int u)
{
if(dp[u]!=-1)
return dp[u];
int res=0;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
f(v);
if(dp[v]%2)// go v then u is p
{
if(res%2==0)//u is p
res=max(res,dp[v]+1);
}
else
{
if(res%2==0)// u is actually n
res=dp[v]+1;
else
res=min(res,dp[v]+1);
}
}
return dp[u]=res;
}
int main()
{
int n,m,k;
memset(dp,-1,sizeof(dp));
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
scanf("%d",&c[i]);
int u,v,ans=inf;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
}
for(int i=1;i<=k;i++)
ans=min(ans,f(c[i]));
puts(ans%2?"A":"B");
return 0;
}