5-2ACM训练题解(Asia Nakhon Pathom Regional Contest)
C-Evolution Game Gym - 102091C by wxh
按单增的维度排序,然后另一个维度DP,就和最初的n^2求最长递增子序列相似。
N^2跑就行
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct data { 4 int a, b; 5 }a[5005]; 6 int F[5005]; 7 int T[5005]; 8 int main() { 9 int N, w; 10 scanf ("%d%d", &N, &w); 11 for (int i = 1; i <= N; i++) { 12 scanf ("%d", &a[i].a); 13 T[i] = a[i].a; 14 a[i].b = i; 15 } 16 sort (a + 1, a + N + 1, [&] (data &x, data &y) -> bool{ 17 return x.a == y.a ? x.b < y.b : x.a < y.a; 18 }); 19 int ans = 0; 20 for (int i = 1; i <= N; i++) { 21 F[i] = 0; 22 for (int j = 1; j <= i; j++) { 23 if (a[j].a < a[i].a && abs(a[j].b - a[i].b) <= w) { 24 F[i] = max(F[i], F[j] + 1); 25 ans = max(ans, F[i]); 26 } 27 } 28 } 29 printf ("%d\n", ans); 30 }
D-Bus Stop Gym - 102091D by ltr
贪心签到,从左往右贪心看能否放车站即可
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 2000005 8 using namespace std; 9 int n,T; 10 int A[N]; 11 int main() 12 { 13 scanf("%d",&T); 14 while(T--) 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++) 18 { 19 scanf("%d",&A[i]); 20 } 21 int la=1,cnt=0; 22 for(int i=2;i<=n;i++) 23 { 24 if(A[i]-A[la]>20) 25 { 26 cnt++,la=i; 27 } 28 if(i==n) 29 { 30 cnt++; 31 } 32 } 33 printf("%d\n",cnt); 34 35 } 36 return 0; 37 }
E-How Many Groups Gym - 102091E by ltr
dp,我们先将数组排序,然后设定dp数组f[i][j][k],表示从1~i中用了j次操作,且i-1的状态为k(0表示不变,1表示-1,2表示+1),然后转移即可,在代码里我用的滚动数组替代第一维。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 105 8 using namespace std; 9 int T,n,A[N],f[2][3][3]; 10 int main() 11 { 12 scanf("%d",&T); 13 int cnt=0; 14 while(T--) 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++) 18 { 19 scanf("%d",&A[i]); 20 } 21 sort(A+1,A+n+1); 22 int ans=1; 23 int nw=1,la=0; 24 memset(f,0,sizeof(f)); 25 f[nw][0][0]=1; 26 f[nw][1][1]=1; 27 f[nw][1][2]=1; 28 for(int i=2;i<=n;i++) 29 { 30 nw^=1,la^=1; 31 memset(f[nw],0,sizeof(f[nw])); 32 if(A[i]-A[i-1]<=2) 33 { 34 f[nw][0][0]=max(f[nw][0][0],f[la][0][0]+1); 35 f[nw][1][0]=max(f[nw][1][0],f[la][1][0]+1); 36 f[nw][2][0]=max(f[nw][2][0],f[la][2][0]+1); 37 } 38 if(abs(A[i]-(A[i-1]-1))<=2) 39 { 40 f[nw][1][0]=max(f[nw][1][0],f[la][1][1]+1); 41 f[nw][2][0]=max(f[nw][2][0],f[la][2][1]+1); 42 } 43 if(abs(A[i]-(A[i-1]+1))<=2) 44 { 45 f[nw][1][0]=max(f[nw][1][0],f[la][1][2]+1); 46 f[nw][2][0]=max(f[nw][2][0],f[la][2][2]+1); 47 } 48 if(abs(A[i]-1-A[i-1])<=2) 49 { 50 f[nw][1][1]=max(f[nw][1][1],f[la][0][0]+1); 51 f[nw][2][1]=max(f[nw][2][1],f[la][1][0]+1); 52 } 53 if(abs(A[i]+1-A[i-1])<=2) 54 { 55 f[nw][1][2]=max(f[nw][1][2],f[la][0][0]+1); 56 f[nw][2][2]=max(f[nw][2][2],f[la][1][0]+1); 57 } 58 59 if(abs((A[i]-1)-(A[i-1]-1))<=2) 60 { 61 f[nw][2][1]=max(f[nw][2][1],f[la][1][1]+1); 62 } 63 if(abs((A[i]+1)-(A[i-1]+1))<=2) 64 { 65 f[nw][2][2]=max(f[nw][2][2],f[la][1][2]+1); 66 } 67 68 if(abs((A[i]-1)-(A[i-1]+1))<=2) 69 { 70 f[nw][2][1]=max(f[nw][2][1],f[la][1][2]+1); 71 } 72 if(abs((A[i]+1)-(A[i-1]-1))<=2) 73 { 74 f[nw][2][2]=max(f[nw][2][2],f[la][1][1]+1); 75 } 76 if(!f[nw][0][0]) f[nw][0][0]=1; 77 for(int j=1;j<=2;j++) 78 { 79 for(int k=0;k<=2;k++) 80 { 81 if(!f[nw][j][k]) f[nw][j][k]=1; 82 ans=max(ans,f[nw][j][k]); 83 } 84 } 85 86 ans=max(ans,f[nw][0][0]); 87 } 88 cnt++; 89 printf("Case %d: %d\n",cnt,ans); 90 } 91 return 0; 92 }
F-Lucky Pascal Triangle Gym - 102091F by wxh
打表找规律,然后递归求解就可以了
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int MOD = 1e9 + 7, Inv2 = 500000004; 4 long long bin[25], D[25]; 5 int Calc(long long a, int L) { 6 if (a <= 7) return 0; 7 int T = a / bin[L]; 8 // long long d = (bin[L] * 2 - a % bin[L] - 1) % MOD; 9 long long ans = (bin[L] * 2 - a % bin[L] - 1) % MOD * ((a % bin[L]) % MOD) % MOD * Inv2 % MOD * (a / bin[L]) % MOD; 10 ans = (ans + 1ll * Calc(a % bin[L], L - 1) * (a / bin[L] + 1) % MOD) % MOD; 11 ans = (ans + 1ll * D[L] * (1 + T) * T % MOD * Inv2 % MOD + bin[L] % MOD * ((bin[L] - 1) % MOD) % MOD * Inv2 % MOD * T * (T - 1) % MOD * Inv2 % MOD) % MOD; 12 return ans; 13 } 14 int main() { 15 int N; 16 scanf ("%d", &N); 17 long long a = 0; 18 bin[0] = 1; 19 for (int i = 1; i <= 22; i++) bin[i] = bin[i - 1] * 7; 20 // for (int i = 1; i <= 22; i++) printf ("%lld\n", bin[i]); 21 for (int i = 1; i <= 22; i++) D[i] = Calc(bin[i] - 1, i - 1); 22 for (int i = 1; i <= N; i++) { 23 scanf ("%lld", &a); 24 int L; 25 for (L = 22; L >= 1; L--) { 26 if (a >= bin[L]) 27 break; 28 } 29 printf ("Case %d: %d\n", i, Calc(a + 1, L)); 30 } 31 }
G-Communication Gym - 102091G by ltr
题意说的很奇怪,算是“心灵相通”A掉的,在这里大概说一下题意,就是一开始有n个办公室,之间有单向边,如果他们之间都能直接或间接到达,则他们是一个部门,问你总共有多少部门。
说白了就是一个数联通块的题……tarjan板子放上去就可以了
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 205 8 using namespace std; 9 int T,n,m,zz,a[N]; 10 struct ro{ 11 int to,next; 12 }road[N*N]; 13 void build(int x,int y) 14 { 15 zz++; 16 road[zz].to=y; 17 road[zz].next=a[x]; 18 a[x]=zz; 19 } 20 int dfn[N],low[N],zz1,st[N],top,zz2; 21 bool rd[N]; 22 void tarjan(int x) 23 { 24 zz1++; 25 dfn[x]=low[x]=zz1; 26 top++; 27 st[top]=x; 28 rd[x]=1; 29 for(int i=a[x];i;i=road[i].next) 30 { 31 int y=road[i].to; 32 if(!dfn[y]) 33 { 34 tarjan(y); 35 low[x]=min(low[x],low[y]); 36 } 37 else if(rd[y]) 38 { 39 low[x]=min(low[x],dfn[y]); 40 } 41 } 42 if(low[x]==dfn[x]) 43 { 44 zz2++; 45 int v; 46 do{ 47 v=st[top]; 48 top--; 49 rd[v]=0; 50 }while(dfn[v]!=low[v]); 51 } 52 } 53 int main() 54 { 55 scanf("%d",&T); 56 while(T--) 57 { 58 scanf("%d%d",&n,&m); 59 zz=0; 60 memset(a,0,sizeof(a)); 61 for(int i=1;i<=m;i++) 62 { 63 int x,y; 64 scanf("%d%d",&x,&y); 65 x++,y++; 66 build(x,y); 67 } 68 zz1=zz2=0; 69 memset(dfn,0,sizeof(dfn)); 70 memset(low,0,sizeof(low)); 71 for(int i=1;i<=n;i++) 72 { 73 if(!dfn[i]) 74 { 75 tarjan(i); 76 } 77 } 78 printf("%d\n",zz2); 79 } 80 return 0; 81 }
J-Floating-point Hazard Gym - 102091J by wxh
$$\sum_{i=low}^{high} {(\sqrt[3]{(i+10^{-15})}-\sqrt[3]{i})} \approx \sum_{i=low}^{high} {\lim_{x->0} (\sqrt[3]{(i+x)}-\sqrt[3]{i})} = \sum_{i=low}^{high}{f'(i) \times 10^{-15}}$$
然后按导数求就可以了
1 #include <bits/stdc++.h> 2 using namespace std; 3 int main() { 4 long long a, b; 5 while (scanf ("%lld%lld", &a, &b) != EOF) { 6 if (a == 0 && b == 0) break; 7 double ans = 0; 8 for (int i = a; i <= b; i++) { 9 ans += 1. / 3 * pow(i, -2. / 3); 10 } 11 printf ("%.5E\n", ans * 1e-15); 12 } 13 }
K-The Sream of Corning 2 Gym - 102091K by ltr
这道题好像解法挺多,我是直接将输入的值离散化,将操作1拆成加入和删除两个操作,然后在线段树上找前缀和>=K的第一个值,不难,但是训练的时候没看到……
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<map> 7 #include<algorithm> 8 #define N 100005 9 using namespace std; 10 int T,m,zz; 11 struct qu{ 12 int id,op,x,y,z; 13 }que[N*2]; 14 bool cmp(const qu &a,const qu &b) 15 { 16 if(a.x!=b.x)return a.x<b.x; 17 return a.op<b.op; 18 } 19 int zz2,B[N]; 20 struct no{ 21 int left,right,mid,size; 22 }node[N*4]; 23 void build(int left,int right,int x) 24 { 25 node[x].left=left,node[x].right=right; 26 node[x].size=0; 27 if(left==right) 28 { 29 return; 30 } 31 int mid=(left+right)>>1; 32 node[x].mid=mid; 33 build(left,mid,x<<1); 34 build(mid+1,right,x<<1|1); 35 } 36 map<int,int> ma; 37 void add(int x,int to,int da) 38 { 39 if(node[x].left==node[x].right) 40 { 41 node[x].size+=da; 42 return; 43 } 44 int mid=node[x].mid; 45 if(to>mid) add(x<<1|1,to,da); 46 else add(x<<1,to,da); 47 node[x].size=node[x<<1].size+node[x<<1|1].size; 48 } 49 int work(int x,int da) 50 { 51 if(node[x].left==node[x].right)return node[x].left; 52 int mid=node[x].mid; 53 if(node[x<<1].size>=da) 54 { 55 return work(x<<1,da); 56 } 57 else return work(x<<1|1,da-node[x<<1].size); 58 } 59 int ans[N]; 60 int main() 61 { 62 scanf("%d",&T); 63 int cnt=0; 64 while(T--) 65 { 66 cnt++; 67 scanf("%d",&m); 68 zz=0; 69 zz2=0; 70 int zz3=0; 71 ma.clear(); 72 for(int i=1;i<=m;i++) 73 { 74 zz++; 75 scanf("%d",&que[zz].op); 76 que[zz].id=i; 77 if(que[zz].op==1) 78 { 79 scanf("%d%d%d",&que[zz].x,&que[zz].y,&que[zz].z); 80 zz++; 81 que[zz].id=i,que[zz].op=3,que[zz].x=que[zz-1].z; 82 que[zz].y=que[zz-1].y; 83 if(!ma.count(que[zz].y)) 84 { 85 ma[que[zz].y]=1; 86 zz2++; 87 B[zz2]=que[zz].y; 88 } 89 } 90 else 91 { 92 zz3++; 93 que[zz].id=zz3; 94 scanf("%d%d",&que[zz].x,&que[zz].y); 95 } 96 } 97 sort(que+1,que+zz+1,cmp); 98 sort(B+1,B+zz2+1); 99 for(int i=1;i<=zz2;i++) ma[B[i]]=i; 100 build(1,zz2,1); 101 for(int i=1;i<=zz;i++) 102 { 103 if(que[i].op==1) 104 { 105 add(1,ma[que[i].y],1); 106 } 107 else if(que[i].op==3) 108 { 109 add(1,ma[que[i].y],-1); 110 } 111 else 112 { 113 if(node[1].size>=que[i].y) ans[que[i].id]=B[work(1,que[i].y)]; 114 else ans[que[i].id]=-1; 115 } 116 } 117 printf("Case %d:\n",cnt); 118 for(int i=1;i<=zz3;i++) 119 { 120 printf("%d\n",ans[i]); 121 } 122 } 123 return 0; 124 }
L-Largest Allowed Area Gym - 102091L by ltr
一开始是枚举所选矩形左上角,然后利用二维前缀和进行二分,然后发现T了……
之后发现了一个性质,就是(x,y)的最优解最多为(x,y+1)的最优解+1,然后又加上快读就过了。
A了之后试着把第一次的代码加上快读和二分左端点优化再交,也过了。
之后看了一下网上的题解,说是单调队列,我理解的就是每一行从右往左遍历,用单调队列维护最优右端点。复杂度很优秀。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 1005 8 using namespace std; 9 int n,T,m,ma[N][N],sm[N][N]; 10 int get(int x,int y,int ll,int rr) 11 { 12 int l=ll,r=min(rr,min(n-x+1,m-y+1)),mid,ans=1; 13 while(l<=r) 14 { 15 mid=(l+r)>>1; 16 17 if(sm[x+mid-1][y+mid-1]-sm[x+mid-1][y-1]-sm[x-1][y+mid-1]+sm[x-1][y-1]<=1) ans=mid,l=mid+1; 18 else r=mid-1; 19 } 20 return ans; 21 } 22 char xch,xB[1<<15],*xS=xB,*xTT=xB; 23 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++) 24 inline int read() 25 { 26 int x=0,f=1;char ch=getc(); 27 while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} 28 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} 29 return x*f; 30 } 31 int main() 32 { 33 T=read(); 34 while(T--) 35 { 36 n=read(),m=read(); 37 for(register int i=1,j;i<=n;++i) 38 { 39 int su=0; 40 for(j=1;j<=m;++j) 41 { 42 ma[i][j]=read(); 43 su+=ma[i][j]; 44 sm[i][j]=sm[i-1][j]+su; 45 } 46 } 47 int ans=1; 48 for(register int i=1,j;i<=n;++i) 49 { 50 int la=1; 51 for(j=m-1;j;--j) 52 { 53 la=get(i,j,1,la+1); 54 ans=max(ans,la); 55 } 56 } 57 printf("%d\n",ans); 58 } 59 return 0; 60 }
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 1005 8 using namespace std; 9 int n,T,m,ma[N][N],sm[N][N]; 10 int get(int x,int y,int ll) 11 { 12 int l=ll,r=min(n-x+1,m-y+1),mid,ans=1; 13 while(l<=r) 14 { 15 mid=(l+r)>>1; 16 17 if(sm[x+mid-1][y+mid-1]-sm[x+mid-1][y-1]-sm[x-1][y+mid-1]+sm[x-1][y-1]<=1) ans=mid,l=mid+1; 18 else r=mid-1; 19 } 20 return ans; 21 } 22 char xch,xB[1<<15],*xS=xB,*xTT=xB; 23 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++) 24 inline int read() 25 { 26 int x=0,f=1;char ch=getc(); 27 while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} 28 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} 29 return x*f; 30 } 31 int main() 32 { 33 T=read(); 34 while(T--) 35 { 36 n=read(),m=read(); 37 for(register int i=1,j;i<=n;++i) 38 { 39 int su=0; 40 for(j=1;j<=m;++j) 41 { 42 ma[i][j]=read(); 43 su+=ma[i][j]; 44 sm[i][j]=sm[i-1][j]+su; 45 } 46 } 47 int ans=1; 48 for(register int i=1,j;i<=n;++i) 49 { 50 int la=1; 51 for(j=m-1;j;--j) 52 { 53 la=get(i,j,ans); 54 ans=max(ans,la); 55 } 56 } 57 printf("%d\n",ans); 58 } 59 return 0; 60 }