Educational Codeforces Round 59 (Rated for Div. 2)
题意:给你一个长度300的,只由1-9构成的字符串,问你是否能按顺序分成至少2部分,满足每个数都比前一个数大
题解:由于没有0,所以拆分后的数,只要满足位数比你多,就一定能完成.
对于长度为2的单独判断,其他的直接分成2段:第一位和剩下所有
1 #include<bits/stdc++.h> 2 using namespace std; 3 int T,n; 4 char s[305]; 5 int main() 6 { 7 scanf("%d",&T); 8 while (T--) 9 { 10 scanf("%d",&n); 11 scanf("%s",s+1); 12 if (n==2) 13 { 14 if (s[1]>=s[2]) printf("NO\n");else 15 printf("YES\n2\n%c %c\n",s[1],s[2]); 16 }else 17 { 18 printf("YES\n2\n%c ",s[1]); 19 for (int i=2;i<=n;i++) printf("%c",s[i]); 20 printf("\n"); 21 } 22 } 23 }
题意:定义s(x)等于x的每一位之和的s(),直到小于10,例如s(38)=s(3+8)=s(11)=s(1+1)=s(2),
现在给你多组k,x,问你满足s(n)=x的数中第k大的是多少
题解:动手写写s(10)=1,s(11)=2,s(18)=9,s(19)=1,s(20)=2,s(27)=9,s(28)=1
显然发现9个一循环,所以答案就是(k-1)*9+x
1 #include<bits/stdc++.h> 2 using namespace std; 3 int T; 4 long long n,m; 5 int main() 6 { 7 scanf("%d",&T); 8 while (T--) 9 { 10 scanf("%lld%lld",&n,&m); 11 printf("%lld\n",(n-1)*9+m); 12 } 13 }
题意:给你一个2e5的只有小写字母的字符串,每个字母都有一个权值,再给你一个K,表示连续相同的字符最多只能取k个
例如 k=3的时候,aaaa只能最多选择3个连续的进行选择,问最多能得到的权值是多少
题意:对于每段相同的字母,排序后找最大的k个,贪心选择一下就好了
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k; 4 long long ans,a[200005]; 5 char s[200005]; 6 int main() 7 { 8 scanf("%d%d",&n,&k); 9 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 10 scanf("%s",s+1); 11 for (int i=1,j=1;i<=n;i=j) 12 { 13 while (j<=n && s[i]==s[j]) j++; 14 sort(a+i,a+j); 15 int p=max(j-k,i); 16 for (int t=j-1;t>=p;t--) ans+=a[t]; 17 } 18 printf("%lld",ans); 19 }
题意:给一个n*n(n<=5200)的01矩阵,问你能不能分成(n/x) * (n/x)的矩阵若干个,使得每个矩阵内部都是0或者都是1,问你最大x是多少
题解:从大到小枚举到x,暴力判断每个子矩阵是否一样,感觉并太好卡暴力,因为要保证一个较小的x是答案,数据会在x更大的更快退出
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,ans; 4 char a[5202]; 5 string t[520500]; 6 int dfs(int x) 7 { 8 for(int i=0;i<n;i+=x) 9 for(int j=0;j<n;j+=x) 10 { 11 char ch=t[i][j]; 12 for(int k=i;k<i+x;k++) 13 for(int p=j;p<j+x;p++) if(t[k][p]!=ch) return 0; 14 } 15 return 1; 16 } 17 int main() 18 { 19 scanf("%d",&n); 20 for (int i=0;i<n;i++) 21 { 22 string a; 23 cin>>a; 24 //scanf("%s",a+1); 25 int len=a.size(); 26 for (int j=0;j<len;j++) 27 { 28 if(a[j]=='0') t[i]+="0000"; 29 if(a[j]=='1') t[i]+="0001"; 30 if(a[j]=='2') t[i]+="0010"; 31 if(a[j]=='3') t[i]+="0011"; 32 if(a[j]=='4') t[i]+="0100"; 33 if(a[j]=='5') t[i]+="0101"; 34 if(a[j]=='6') t[i]+="0110"; 35 if(a[j]=='7') t[i]+="0111"; 36 if(a[j]=='8') t[i]+="1000"; 37 if(a[j]=='9') t[i]+="1001"; 38 if(a[j]=='A') t[i]+="1010"; 39 if(a[j]=='B') t[i]+="1011"; 40 if(a[j]=='C') t[i]+="1100"; 41 if(a[j]=='D') t[i]+="1101"; 42 if(a[j]=='E') t[i]+="1110"; 43 if(a[j]=='F') t[i]+="1111"; 44 } 45 } 46 for (int i=n;i>=1;i--) 47 { 48 if (n%i==0) 49 if (dfs(i)) {ans=i;break;} 50 } 51 printf("%d",ans); 52 }
题意:给你一个长度100的01字符串,每次可以选连续相同的任意个字符消除,消除后两边的字符接上去,
消去一个长度的字符串会得到一个收益,问消除完所有的能得到的最大收益是多少
题解:典型的区间dp,dp[i][j][k]表示删除从i到j的字符串,该子串前k位和第一位一样的时候,消除的收益
2种转移:直接消除这k个 dp[i][j][k]=a[k]+dp[i+1][j][1]
消除中间的,让前后连起来再消除 dp[i][j][k]=dp[i+1][q-1][1]+dp[q][j][k+1](s[q]==s[i])
答案就是dp[1][n][1]
1 #include<bits/stdc++.h> 2 #define lld long long 3 #define N 102 4 using namespace std; 5 lld a[N],f[N][N][N]; 6 char s[N]; 7 int n; 8 lld why(int st,int ed,int p) 9 { 10 if (st>ed) return 0; 11 if (f[st][ed][p]!=-1) return f[st][ed][p]; 12 if (st==ed) 13 { 14 f[st][ed][p]=a[p]; 15 return f[st][ed][p]; 16 } 17 f[st][ed][p]=a[p]+why(st+1,ed,1); 18 for (int i=st+1;i<=ed;i++) 19 if (s[i]==s[st]) 20 { 21 f[st][ed][p]=max(f[st][ed][p],why(st+1,i-1,1)+why(i,ed,p+1)); 22 } 23 return f[st][ed][p]; 24 } 25 int main() 26 { 27 scanf("%d",&n); 28 scanf("%s",s+1); 29 for (int i=1;i<=n;i++) scanf("%lld",&a[i]); 30 memset(f,-1,sizeof(f)); 31 printf("%lld",why(1,n,1)); 32 }
题意:有500张信用卡,你每个月只能选择得到最多一张,a,b,k表示办这张卡的时候你得到a元,以后每个月还b元,共k个月
你可以在任意时刻跑路(凭本事借的为什么要还),问你最多能带多少钱跑路
题解:看起来很像费用流啊!,我们可以对每张信用卡build(S,i,1,0),再定义这是倒数第几个月build(j,T,1,0)
信用卡对月份连接的意思就是,这张卡i在倒数第j个月的时候借了能获得的钱,(可能k大于j,还不完就跑)
这样就能得到答案,但是复杂度有点不允许,因为边数太多.
再发现这其实也是一个二分图且流量都一样为1,我们可以直接用二分图的最大权匹配(KM)来做,就少了一个n的代价
好像其实这道题dp做法n*n的?快的飞起?
(hsj板子218ms)
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=500+5; 5 const int inf=0x3f3f3f3f; 6 const ll linf=1e18; 7 8 int n; 9 10 ll w[maxn][maxn],slack[maxn],x[maxn],y[maxn]; 11 ll prev_x[maxn],prev_y[maxn],son_y[maxn],par[maxn]; 12 ll lx,ly,pop; 13 void adjust(int v) 14 { 15 son_y[v]=prev_y[v]; 16 if(prev_x[son_y[v]]!=-2)adjust(prev_x[son_y[v]]); 17 } 18 19 bool findd(int v) 20 { 21 for(ll i=0;i<pop;i++) 22 if(prev_y[i]==-1) 23 { 24 if(slack[i]>x[v]+y[i]-w[v][i]) 25 { 26 slack[i]=x[v]+y[i]-w[v][i]; 27 par[i]=v; 28 } 29 if(x[v]+y[i]==w[v][i]) 30 { 31 prev_y[i]=v; 32 if(son_y[i]==-1) 33 { 34 adjust(i); 35 return 1; 36 } 37 if(prev_x[son_y[i]]!=-1) continue; 38 prev_x[son_y[i]]=i; 39 if(findd(son_y[i])) return 1; 40 } 41 } 42 return 0; 43 } 44 45 ll km() 46 { 47 ll i,j,m; 48 for(i=0;i<pop;i++) 49 { 50 son_y[i]=-1; 51 y[i]=0; 52 } 53 for(i=0;i<pop;i++) 54 { 55 x[i]=0; 56 for(j=0;j<pop;j++) x[i]=max(x[i],w[i][j]); 57 } 58 bool flag; 59 for(i=0;i<pop;i++) 60 { 61 for(j=0;j<pop;j++) 62 { 63 prev_x[j]=prev_y[j]=-1; 64 slack[j]=linf; 65 } 66 prev_x[i]=-2; 67 if(findd(i))continue; 68 flag=false; 69 while(!flag) 70 { 71 m=inf; 72 for(j=0;j<pop;j++) 73 if(prev_y[j]==-1) m=min(m,slack[j]); 74 for(j=0;j<pop;j++) 75 { 76 if(prev_x[j]!=-1) x[j]-=m; 77 if(prev_y[j]!=-1) y[j]+=m;else slack[j]-=m; 78 } 79 for(j=0;j<pop;j++) 80 if(prev_y[j]==-1&&!slack[j]) 81 { 82 prev_y[j]=par[j]; 83 if(son_y[j]==-1) 84 { 85 adjust(j); 86 flag=true; 87 break; 88 } 89 prev_x[son_y[j]]=j; 90 if(findd(son_y[j])) 91 { 92 flag=true; 93 break; 94 } 95 } 96 } 97 } 98 ll ans=0; 99 for (int i=0;i<pop;i++)ans+=w[son_y[i]][i]; 100 return ans; 101 } 102 103 ll a,b,k; 104 int main() 105 { 106 //freopen("in.txt","r",stdin); 107 scanf("%d",&n); 108 pop=n; 109 for (int i=0;i<n;i++) 110 { 111 scanf("%lld%lld%lld",&a,&b,&k); 112 for(int j=0;j<n;j++) 113 { 114 ll vv=a-min(k,(ll)j)*b; 115 w[i][j]=max(vv,0LL); 116 } 117 } 118 printf("%lld\n",km()); 119 return 0; 120 }
(kuangbin板子2136ms)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 505 4 #define lld long long 5 const lld INF = 1e18; 6 int nx,ny;//两边的点数 7 lld g[N][N];//二分图描述 8 int linker[N]; 9 lld lx[N],ly[N];//y中各点匹配状态,x,y中的点标号 10 lld slack[N]; 11 bool visx[N],visy[N]; 12 bool DFS(int x) 13 { 14 visx[x] = true; 15 for(int y = 0; y < ny; y++) 16 { 17 if(visy[y])continue; 18 lld tmp = lx[x] + ly[y] - g[x][y]; 19 if(tmp == 0) 20 { 21 visy[y] = true; 22 if(linker[y] == -1 || DFS(linker[y])) 23 { 24 linker[y] = x; 25 return true; 26 } 27 } 28 else if(slack[y] > tmp) slack[y] = tmp; 29 } 30 return false; 31 } 32 lld KM() 33 { 34 memset(linker,-1,sizeof(linker)); 35 //memset(ly,0,sizeof(ly)); 36 for(int i = 0;i < nx;i++) 37 { 38 lx[i] = -INF; 39 for(int j = 0;j < ny;j++) 40 if(g[i][j] > lx[i]) lx[i] = g[i][j]; 41 } 42 for(int x = 0;x < nx;x++) 43 { 44 for(int i = 0;i < ny;i++) slack[i] = INF; 45 while(true) 46 { 47 for (int i=0;i<nx;i++) visx[i]=0; 48 for (int i=0;i<ny;i++) visy[i]=0; 49 if(DFS(x))break; 50 lld d = INF; 51 for(int i = 0;i < ny;i++) 52 if(!visy[i] && d > slack[i]) d = slack[i]; 53 for(int i = 0;i < nx;i++) 54 if(visx[i]) lx[i] -= d; 55 for(int i = 0;i < ny;i++) 56 if(visy[i])ly[i] += d; else slack[i] -= d; 57 58 } 59 } 60 lld res = 0; 61 for(int i = 0;i < ny;i++) 62 if(linker[i] != -1) res += g[linker[i]][i]; 63 return res; 64 } 65 lld a,b,k; 66 int main() 67 { 68 //freopen("in.txt","r",stdin); 69 int n; 70 while(scanf("%d",&n) == 1) 71 { 72 for (int i=0;i<n;i++) 73 { 74 scanf("%lld%lld%lld",&a,&b,&k); 75 for(int j=0;j<n;j++) 76 { 77 lld vv=a-min(k,(lld)j)*b; 78 g[i][j]=max(vv,0LL); 79 } 80 } 81 nx = ny = n; 82 printf("%lld\n",KM()); 83 } 84 return 0; 85 }
题意:给一个n(3e5)个元素的数组ci,和一个n元素的严格上升的数组di和一个数a,求最大的a*(r-l+1)-sigma(i=l to r)c[i]-gap(l,r);
gap(l,r)=max( (d[i+1]-d[i])^2 )(i= l to r)
题解:首先可把a放进每一项里,a*(r-l+1)-sigma(i=l to r)c[i] 变成 sigma(i=l to r)a-c[i],这个用线段树就可以维护最大连续和
对于gap,我们可以统计每个d[i+1]-d[i]能管的到的最长区间是多少,用单调栈O(n)预处理
再枚举这些最大区间求区间里最大连续和就好.
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int N = 3e5 + 10; 5 struct tree 6 { 7 LL sum, rmx, lmx, mx; 8 }sgt[N << 2]; 9 int c[N], d[N], diff[N], a, n, l[N], r[N]; 10 long long ans; 11 void pushup(int rt) 12 { 13 sgt[rt].sum = sgt[rt << 1].sum + sgt[rt << 1 | 1].sum; 14 sgt[rt].mx = max(sgt[rt << 1].mx, sgt[rt << 1 | 1].mx); 15 sgt[rt].lmx = max(sgt[rt << 1].lmx, sgt[rt << 1].sum + sgt[rt << 1 | 1].lmx); 16 sgt[rt].rmx = max(sgt[rt << 1 | 1].rmx, sgt[rt << 1 | 1].sum + sgt[rt << 1].rmx); 17 sgt[rt].mx = max(sgt[rt].mx, sgt[rt << 1].rmx + sgt[rt << 1 | 1].lmx); 18 } 19 20 void build(int rt, int l, int r) 21 { 22 if(l == r) 23 { 24 sgt[rt].sum = sgt[rt].lmx = sgt[rt].rmx = sgt[rt].mx = c[l]; 25 return; 26 } 27 int mid = l + r >> 1; 28 build(rt << 1, l, mid); 29 build(rt << 1 | 1, mid + 1, r); 30 pushup(rt); 31 } 32 tree query(int rt, int l, int r, int L, int R) 33 { 34 if(L <= l && r <= R) return sgt[rt]; 35 int mid = l + r >> 1; 36 if(R <= mid) return query(rt << 1, l, mid, L, R); 37 if(L > mid) return query(rt << 1 | 1, mid + 1, r, L, R); 38 tree u = query(rt << 1, l, mid, L, R), v = query(rt << 1 | 1, mid + 1, r, L, R), o; 39 o.sum = u.sum + v.sum; 40 o.mx = max(u.mx, v.mx); 41 o.mx = max(o.mx, u.rmx + v.lmx); 42 o.lmx = max(u.lmx, u.sum + v.lmx); 43 o.rmx = max(v.rmx, v.sum + u.rmx); 44 return o; 45 } 46 struct node 47 { 48 int val, id; 49 }; 50 int main() 51 { 52 scanf("%d%d",&n,&a); 53 for (int i=1;i<=n;i++) 54 { 55 scanf("%d%d",&d[i],&c[i]); 56 c[i]=a-c[i]; 57 ans=max(ans,(LL)c[i]); 58 } 59 for (int i=1;i<n;i++) diff[i]=d[i+1]-d[i]; 60 build(1,1,n); 61 stack<node> stk; 62 stk.push({(int)1e9, 0}); 63 for (int i=1;i<n;i++) 64 { 65 while (stk.top().val<=diff[i]) stk.pop(); 66 l[i]=stk.top().id+1; 67 stk.push({diff[i],i}); 68 } 69 while (!stk.empty()) stk.pop(); 70 stk.push({(int)1e9,n}); 71 for (int i = n - 1; i; --i) 72 { 73 while(stk.top().val <= diff[i]) stk.pop(); 74 r[i] = stk.top().id; 75 stk.push({diff[i], i}); 76 } 77 for(int i=1;i<n;i++) 78 ans=max(ans, query(1,1,n,l[i],r[i]).mx - (LL)diff[i] * diff[i]); 79 printf("%lld\n",ans); 80 return 0; 81 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步