Educational Codeforces Round 54
这套题不难,但是场上数据水,导致有很多叉点
A.
因为是让求删掉一个后字典序最小,那么当a[i]>a[i+1]的时候,删掉a[i]一定最优!这个题有个叉点,当扫完一遍如果没有满足条件的,就删去最后一个字符。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <set> 6 #include <map> 7 #include <vector> 8 #include <queue> 9 #include <cmath> 10 #include <cstdlib> 11 #include <stack> 12 13 using namespace std; 14 const double eps = 1e-6; 15 const int MOD=1e9+7; 16 typedef long long LL; 17 typedef unsigned long long ull; 18 const int INF=2147000000; 19 const LL inf = 1e18; 20 LL gcd(LL a,LL b){ 21 if(!b)return a; 22 return gcd(b,a%b); 23 } 24 LL lcm(LL a,LL b){ 25 return a/gcd(a,b)*b; 26 } 27 const int maxn=2e5+100; 28 char s[maxn]; 29 int n; 30 int main(){ 31 scanf("%d",&n); 32 scanf("%s",s); 33 int pos=-1; 34 for(int i=0;i<n-1;i++){ 35 if(s[i+1]<s[i]){ 36 pos=i; 37 break; 38 } 39 } 40 if(pos==-1) 41 pos=n-1; 42 for(int i=0;i<n;i++) 43 if(i!=pos) 44 printf("%c",s[i]); 45 return 0; 46 }
B.
当n是偶数的时候一定是每次都减2,也就是n/2.当n奇数的时候,就暴力减质数一直减到是偶数或者为0.注意要特判当前n是不是质数。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <set> 6 #include <map> 7 #include <vector> 8 #include <queue> 9 #include <cmath> 10 #include <cstdlib> 11 #include <stack> 12 13 using namespace std; 14 const double eps = 1e-6; 15 const int MOD=1e9+7; 16 typedef long long LL; 17 typedef unsigned long long ull; 18 const int INF=2147000000; 19 const LL inf = 1e18; 20 LL gcd(LL a,LL b){ 21 if(!b)return a; 22 return gcd(b,a%b); 23 } 24 LL lcm(LL a,LL b){ 25 return a/gcd(a,b)*b; 26 } 27 const int maxn=2e5+100; 28 29 int prime[maxn]; 30 int vis[maxn]; 31 int num; 32 int init(int n){ 33 int m = (int)sqrt(n); 34 vis[1]=1; 35 36 for(int i = 2;i<=m;i++){ 37 for(int j =i*i; j<=n;j+=i){ 38 vis[j]=1; 39 } 40 } 41 for(int i=2;i<=n;i++){ 42 if(!vis[i]){ 43 num++; 44 prime[num] = i; 45 } 46 } 47 return num; 48 } 49 bool judge(LL x){ 50 int m =(int)sqrt(x); 51 for(int i=2;i<=m+1;i++){ 52 if(x%i==0) 53 return false; 54 } 55 return true; 56 } 57 LL n; 58 int 59 main(){ 60 cin>>n; 61 LL ans=0; 62 init(2e5); 63 if(n%2==0){ 64 cout<<n/2<<endl; 65 return 0; 66 } 67 bool ok=1; 68 while(n%2){ 69 if(judge(n)){ 70 ans+=1; 71 ok=0; 72 break; 73 } 74 75 int flag=0; 76 for(int i=1;i<=num&&prime[i]<=n;i++){ 77 if(n%prime[i]==0){ 78 // printf("!!%d\n",prime[i]); 79 flag=prime[i]; 80 break; 81 } 82 } 83 //printf("%d\n",flag); 84 if(!flag)flag=n; 85 n-=flag; 86 ans++; 87 } 88 if(ok) 89 ans+=n/2; 90 cout<<ans<<endl; 91 return 0; 92 }
C.
这个题就是解一个一元二次方程,应该也可以三分来做。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <set> 6 #include <map> 7 #include <vector> 8 #include <queue> 9 #include <cmath> 10 #include <cstdlib> 11 #include <stack> 12 13 using namespace std; 14 const double eps = 1e-6; 15 const int MOD=1e9+7; 16 typedef long long LL; 17 typedef unsigned long long ull; 18 const int INF=2147000000; 19 const LL inf = 1e18; 20 LL gcd(LL a,LL b){ 21 if(!b)return a; 22 return gcd(b,a%b); 23 } 24 LL lcm(LL a,LL b){ 25 return a/gcd(a,b)*b; 26 } 27 int main(){ 28 int T; 29 scanf("%d",&T); 30 31 int d; 32 for(int kas=1;kas<=T;kas++){ 33 scanf("%d",&d); 34 double del = d*d - 4*d; 35 if(del<0){ 36 printf("N\n"); 37 }else if(del == 0){ 38 double ans=(double)d/2; 39 40 printf("Y %.9f %.9f\n",ans,(double)(d-ans)); 41 }else{ 42 double ans1 = (double)(d+sqrt(del))/2; 43 if(ans1<=d){ 44 printf("Y %.9f %.9f\n",ans1,(double)(d-ans1)); 45 }else{ 46 double ans1 = (double)(d-sqrt(del))/2; 47 if(ans1<0){ 48 printf("N\n"); 49 }else 50 printf("Y %.9f %.9f\n",ans1,(double)(d-ans1)); 51 } 52 } 53 } 54 return 0; 55 }
D.
最短路+贪心;我们先跑出最短路树来,如果k大于等于最短路树的边数,则树上的边全留下。否则的话就要删树上的边,删哪些呢?从最远(d[u]最大)的边开始删一定是最优的。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <set> 6 #include <map> 7 #include <vector> 8 #include <queue> 9 #include <cmath> 10 #include <cstdlib> 11 #include <stack> 12 13 using namespace std; 14 const double eps = 1e-6; 15 const int MOD=1e9+7; 16 typedef long long LL; 17 typedef unsigned long long ull; 18 const int INF=2147000000; 19 const LL inf = 1e18; 20 LL gcd(LL a,LL b){ 21 if(!b)return a; 22 return gcd(b,a%b); 23 } 24 LL lcm(LL a,LL b){ 25 return a/gcd(a,b)*b; 26 } 27 const int maxn=3e5+100; 28 int head[maxn],to[2*maxn],Next[2*maxn],w[2*maxn],id[2*maxn]; 29 struct Edge{ 30 int from,to,w,id; 31 }; 32 vector<Edge>edges; 33 int sz,n,m,k; 34 void init(){ 35 sz=0; 36 memset(head,-1,sizeof(head)); 37 } 38 void add_edge(int a,int b,int c,int d){ 39 ++sz; 40 to[sz]=b; 41 w[sz]=c; 42 id[sz]=d; 43 Next[sz]=head[a]; 44 head[a]=sz; 45 } 46 struct HeapNode{ 47 int u; 48 LL d; 49 int from; 50 bool operator <(const HeapNode& rhs)const{ 51 return d>rhs.d; 52 } 53 }; 54 int done[maxn],p[maxn]; 55 LL d[maxn]; 56 57 Edge edge[maxn]; 58 59 priority_queue<HeapNode>q; 60 void dij(){ 61 q.push((HeapNode){1,0,-1}); 62 for(int i=0;i<=n;i++) 63 d[i]=inf; 64 while(!q.empty()){ 65 HeapNode x= q.top();q.pop(); 66 if(done[x.u]) 67 continue; 68 done[x.u]=1; 69 d[x.u] = x.d; 70 p[x.u] = x.from; 71 //printf("%d\n",x.from); 72 for(int i=head[x.u];i!=-1;i=Next[i]){ 73 int v = to[i]; 74 if(d[v]>d[x.u]+w[i]){ 75 q.push((HeapNode){v,d[x.u]+w[i],id[i]}); 76 } 77 } 78 } 79 } 80 81 struct Node{ 82 int u; 83 LL d; 84 int from; 85 bool operator <(const Node &rhs)const{ 86 return d<rhs.d; 87 } 88 }; 89 int vis[maxn]; 90 91 priority_queue<Node>Q; 92 93 int main(){ 94 scanf("%d%d%d",&n,&m,&k); 95 96 init(); 97 for(int i=1;i<=m;i++){ 98 int a,b,c; 99 scanf("%d%d%d",&a,&b,&c); 100 add_edge(a,b,c,i); 101 add_edge(b,a,c,i); 102 edge[i]=(Edge){a,b,c,i}; 103 } 104 dij(); 105 for(int i=1;i<=n;i++){ 106 //printf("@%d\n",p[i]); 107 if(p[i]!=-1&& !vis[p[i]]){ 108 edges.push_back(edge[p[i]]); 109 vis[p[i]]=1; 110 Q.push((Node){i,d[i],p[i]}); 111 // printf("!!!%d %d %d %d\n",edge[p[i]].from,edge[p[i]].to,edge[p[i]].w,p[i]); 112 } 113 } 114 if(edges.size()<=k){ 115 printf("%d\n",edges.size()); 116 for(int i=0;i<edges.size();i++){ 117 printf("%d ",edges[i].id); 118 } 119 }else{ 120 int num = edges.size(); 121 while(num>k&&!Q.empty()){ 122 Q.pop(); 123 num--; 124 } 125 printf("%d\n",k); 126 while(!Q.empty()){ 127 printf("%d ",Q.top().from); 128 Q.pop(); 129 } 130 } 131 return 0; 132 }
E.
树状数组或者线段树维护一下。因为每个点的值只可能是来自于它的祖先结点,所以跑dfs的时候,进入这个点的时候更新树状数组,退栈的时候还原树状数组
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 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<Node>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<V[u].size();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<V[u].size();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<n;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 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <cstdlib> 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\n",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\n",(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\n"); 50 }else{ 51 printf("YES\n"); 52 } 53 return 0; 54 }
G.
好像是打反转标记的线段树,留坑