这套题不难,但是场上数据水,导致有很多叉点
A.
因为是让求删掉一个后字典序最小,那么当a[i]>a[i+1]的时候,删掉a[i]一定最优!这个题有个叉点,当扫完一遍如果没有满足条件的,就删去最后一个字符。
1 #include2 #include 3 #include 4 #include 5 #include <set> 6 #include
B.
当n是偶数的时候一定是每次都减2,也就是n/2.当n奇数的时候,就暴力减质数一直减到是偶数或者为0.注意要特判当前n是不是质数。
1 #include2 #include 3 #include 4 #include 5 #include <set> 6 #include
C.
这个题就是解一个一元二次方程,应该也可以三分来做。
1 #include2 #include 3 #include 4 #include 5 #include <set> 6 #include
D.
最短路+贪心;我们先跑出最短路树来,如果k大于等于最短路树的边数,则树上的边全留下。否则的话就要删树上的边,删哪些呢?从最远(d[u]最大)的边开始删一定是最优的。
1 #include2 #include 3 #include 4 #include 5 #include <set> 6 #include
E.
树状数组或者线段树维护一下。因为每个点的值只可能是来自于它的祖先结点,所以跑dfs的时候,进入这个点的时候更新树状数组,退栈的时候还原树状数组
1 #include2 #include 3 #include 4 #include 5 #include 6 7 using namespace std; 8 const int maxn=3e5+100; 9 typedef long long LL; 10 int head[maxn],to[2*maxn],Next[2*maxn]; 11 int n,sz,m; 12 void add_edge(int a,int b){ 13 sz++; 14 to[sz]=b;Next[sz]=head[a];head[a]=sz; 15 } 16 int lowbit(int x){ 17 return x&(-x); 18 } 19 LL sumv[maxn]; 20 void update(int x,int v){ 21 while(x<=n){ 22 sumv[x]+=v; 23 x+=lowbit(x); 24 } 25 } 26 LL query(int x){ 27 LL res=0; 28 while(x){ 29 res+=sumv[x]; 30 x-=lowbit(x); 31 } 32 return res; 33 } 34 struct Node{ 35 int d,x; 36 }; 37 vector V[maxn]; 38 int fa[maxn],dep[maxn]; 39 LL ans[maxn]; 40 41 void dfs(int u,int Fa,int depth){ 42 fa[u]=Fa; 43 dep[u]=depth; 44 for(int i=0;i ){ 45 Node N = V[u][i]; 46 update(min(N.d+depth,n),N.x); 47 } 48 ans[u] = query(n)-query(depth-1); 49 for(int i=head[u];i!=-1;i=Next[i]){ 50 int v=to[i]; 51 if(v==Fa)continue; 52 dfs(v,u,depth+1); 53 } 54 for(int i=0;i ){ 55 Node N = V[u][i]; 56 update(min(N.d+depth,n),-N.x); 57 } 58 } 59 60 int main(){ 61 scanf("%d",&n); 62 memset(head,-1,sizeof(head)); 63 for(int i=1;i ){ 64 int a,b; 65 scanf("%d%d",&a,&b); 66 add_edge(a,b); 67 add_edge(b,a); 68 } 69 scanf("%d",&m); 70 for(int i=1;i<=m;i++){ 71 int v,d,x; 72 scanf("%d%d%d",&v,&d,&x); 73 V[v].push_back((Node){d,x}); 74 } 75 dfs(1,-1,1); 76 for(int i=1;i<=n;i++){ 77 printf("%I64d ",ans[i]); 78 } 79 return 0; 80 }
F.
贪心+分类讨论。
每一页多的为Max,少的为Min。那么一定是用少的将多的分隔开。所以如果大小关系不同则不会产生影响。否则的话,这一页我们要它最左边多出来的那块尽量长。lef=k-lastR;那么Max=Max-lef,Min=Min-1;然后我们分类讨论:
1.ceil(Max/k)-1>Min 则return false;
2.ceil(Max/k)<=Min
则说明右边不会剩下。则lastR=0。
3.ceil(Max/k)==Min-1的话,恰好被分割开,右边会有剩余,但是剩余的长度<=k,属于合法。
lastR= Max%k ==0?k:Max%k
这个也有叉点,要主要Min==Max的情况
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 8 using namespace std; 9 const int maxn = 3e5 + 100; 10 int n, k; 11 int x[maxn][2];//0 x,1 y 12 int state,laststate,lastR; 13 int main(){ 14 scanf("%d%d", &n, &k); 15 for(int i = 1; i <= n; i++){ 16 scanf("%d", &x[i][0]); 17 } 18 for(int i = 1; i <= n; i++){ 19 scanf("%d", &x[i][1]); 20 } 21 bool flag = 1; 22 for(int i = 1; i <= n; i++){ //x >= y state = 1;else state = 0; 23 int Min = min(x[i][0], x[i][1]); 24 int Max = max(x[i][0], x[i][1]); 25 // printf("%d %d ",Min,Max); 26 if(x[i][0] > x[i][1]) 27 state = 1; 28 else if(x[i][0] < x[i][1]) 29 state = 0; 30 else state = -1; 31 if(state == laststate||laststate == -1||state == -1){ 32 int lef = k - lastR; 33 Max = Max - lef; 34 Min = Min - 1; 35 } 36 //printf("%d %d ",(int)ceil((double)Max/k),Min); 37 38 if((int)ceil((double)Max/k)-1 > Min){ 39 flag = 0; 40 break; 41 }else if((int)ceil((double)Max/k) <= Min){ 42 lastR = 0; 43 }else{ 44 lastR = Max%k == 0?k:Max%k; 45 } 46 laststate = state; 47 } 48 if(!flag){ 49 printf("NO "); 50 }else{ 51 printf("YES "); 52 } 53 return 0; 54 }
G.
好像是打反转标记的线段树,留坑