Educational Codeforces Round 59 (Rated for Div. 2)

A. Digits Sequence Dividing

题意:给你一个长度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 } 
View Code

 

B. Digital root

题意:定义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 } 
View Code

 

C. Brutality

题意:给你一个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 } 
View Code

 

D. Compression

题意:给一个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 }
View Code

 

E. Vasya and Binary String

题意:给你一个长度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  }
View Code

 

F. Vasya and Endless Credits

题意:有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 }
View Code

 

        (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 }
View Code

 

G. Vasya and Maximum Profit

题意:给一个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 }
View Code

 

       

 

posted @ 2019-02-27 11:46  口香糖万岁  阅读(160)  评论(0编辑  收藏  举报