个人认为的难度顺序:
A:模拟
M:模拟(当n较大的时候 要考虑到1直接输出 不然会T)
F:贪心。直接取所有石子的平均数,然后少的从多的补,多的去除(一定能补完,因为取平均数是向下取整)
C:直接遍历第一遍循环和最后一遍循环上的所有点距离原点的曼哈顿距离,即可。
D:博弈,给出无向图,每次轮着删除一条边,直到某个人删除任意一条变后,都不能使这个图联通,就GG.
仔细一想,发现:
N个定点,要组成连通图 肯定要至少n-1条边,每个人都是最优的删除方法的话,无论怎么删除顺序,最后哪个输的人是确定的
(即删到n-1条边的时候),然后让那一组都输即可。
L;dfs+拓扑排序判环。
把大小关系转化成有向图连边,大于关系DFS走一次,小于走一次,每个点算出他的子树大小 就是比他小的数的个数。
最后判断输入的2个数是否相同和图是否成环 成环就不可能存在 输出全0串。
以上是模拟赛A的
下面补题
B:
E:
BaoBao Loves Reading |
题意:按照顺序依次从书架上取书到桌上,桌上的容量为k(1<=k<=n),当桌上书本个数小于k时,直接取书,若>=k,则需要把桌上最早阅读的书放回再取,问每次需要取书的次数是多少。
如果直接考虑对于每个k,如果要考虑要取的次数,要对每本书都遍历,比较困难。
但我们逆向思维一手,就会发现,只考虑不需要取的书:肯定是之前书桌上有这本书才不需要取,
而且那本书的阅读次序越靠后越好。(因为)是优先放回最先读的书。
所以我们只需要查找所有2个最近相同的数,如果这2个数之间的数,不同数的个数小于等于k,则书桌容量大于k的时候都不需要取。
我们可以让dp[i]是k==i的时候 不取书的次数。
那么 每次我们查找到2个相邻的数发现不同数等于m,那么所有书桌容量i>=m的不取书数都要+1.
这个操作我们可以用前缀和直接线性处理(每次只让第一个数+1)
然后输出的时候用树状数组来处理查找2最近相同数之间的不同数的个数。
即:输入了一个与之前都不同的数 让这个位置+1,否则让之前相同的数-1,这个位置+1.这样不会影响以后的查询
查询时就直接查询2个数坐标之间数的和即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FI first
#define SE second
typedef pair<ll,ll> P;
const int M = 1e5 + 10;
using namespace std;
int a;
int n;
int c[M];
void add(int x,int d)
{
while(x<=n)
{
c[x]+=d;
x+=x&(-x);
}
}
int ask(int x)
{
int ans=0;
while(x)
{
ans+=c[x];
x-=x&(-x);
}
return ans;
}
int pre[M];
int dp[M];
int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=1;i<M;i++)
dp[i]=0,c[i]=0,pre[i]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
if(pre[a])
{
add(i,1);
add(pre[a],-1);
dp[ask(i)-ask(pre[a]-1)]++;
pre[a]=i;
}
else
{
pre[a]=i;
add(i,1);
}
}
for(int i=1;i<=n;i++)
dp[i]+=dp[i-1];
for(int i=1;i<n;i++)
printf("%d ",n-dp[i]);
printf("%d\n",n-dp[n]);
}
return 0;
}