CF837

A:

题意:

给一堆单词(用’   \space  ’分开),问所有单词中单个单词大写字母最多有多少\

题解:

没什么好说的了主要是读懂题意
代码:

#include<bits/stdc++.h>
using namespace std;
int n;char ch[222];
signed main(){
    scanf("%d",&n);int ans = 0;
    while(scanf("%s",ch + 1) != EOF){
        int cnt = 0;for(int i = 1;i <= strlen(ch + 1);i++){if('A' <= ch[i] && ch[i] <= 'Z')cnt++;}
        ans = max(ans,cnt);
    }
    printf("%d\n",ans);
    return 0;
}

B:

题意:

Berland之旗是满足以下条件的 n × m n \times m n×m 矩形区域:

  • 旗中包含三种颜色,相应地以字母“R”, “G”和“B”表示。

  • 旗中包含三个“长条”,他们的长度和宽度相等(长条1的长度等于长条2的长度,也等于长条3的长度,宽度类似),并且互相平行,同时还平行于旗子的边缘。每个“长条”仅有一种颜色。

  • 每个颜色仅能在一个“长条”中出现。

现在给定由“R”, “G”和“B”构成的 n × m n \times m n×m 矩形区域。请判断它是否是一个正确的Berland之旗,是则输出 “YES”,否则输出"NO"。

题解:

所谓的??之旗就是让你找一个 n n n% 3 = = 0 3==0 3==0 或者 m m m% 3 = = 0 3==0 3==0,然后判断一下是不是分成三部分(想象一下用刀沿着n或m平均切三刀)每一部分颜色都相同且不重复

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, m;char ch[maxn][maxn];int a[maxn][maxn];
bool book[4];
bool check(int x,bool mod){
    if(mod){
        int col = a[1][m / 3 * x + 1];if(book[col])return 0;book[col] = 1;
        for(int i = 1;i <= n;i++){
            for(int j = m / 3 * x + 1;j <= m / 3 * (x + 1);j++){
                // printf("%d %d\n",i,j);
                if(a[i][j] != col)return false;
            }
        }
        return true;
    }
    else{
        int col = a[n / 3 * x + 1][1];if(book[col])return 0;book[col] = 1;
        for(int i = 1;i <= m;i++){
            for(int j = n / 3 * x + 1;j <= n / 3 * (x + 1);j++){
                if(a[j][i] != col)return false;
            }
        }
        return true;    
    }
}
signed main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++){
        scanf("%s",ch[i] + 1);
        for(int j = 1;j <= m;j++)
            a[i][j] = (ch[i][j] == 'R' ? 1 : (ch[i][j] == 'G' ? 2 : 3));
    }
    bool ans = 0;
    if(m % 3 == 0){
        bool res = 1;memset(book,0,sizeof(book));
        for(int i = 0;i <= 2;i++)if(!check(i,1)){res = 0;break;}
        ans |= res;
    }
    if(n % 3 == 0){
        bool res = 1;memset(book,0,sizeof(book));
        for(int i = 0;i <= 2;i++)if(!check(i,0)){res = 0;break;}
        ans |= res;
    }
    puts(ans ? "YES" : "NO");
    return 0;
}

C:

题意:

给一个 a ∗ b a*b ab 的大矩形和 n n n x i ∗ y i x_i*y_i xiyi 的小矩形(可旋转 90 ° 90° 90° ),要求找两个小矩形塞进大矩形中并且面积之和最大

题解:

放矩形的时候让一个的左上角顶在 ( 1 , 1 ) (1,1) (1,1) ,另一个的右下角顶在 ( a , b ) (a,b) (a,b) ,判断能不能放下就好了

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 110;
int x[maxn], y[maxn];
int n, a, b;
bool check(int xi,int yi,int xj,int yj){
    if(xi > a || xj > a || yi > b || yj > b)return false;
    if(xi + xj > a && yi + yj > b)return false;
    return true;
}
signed main(){
    int ans = 0;n = read();a = read(); b = read();
    for(int i = 1;i <= n;i++)x[i] = read(), y[i] = read();
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= n;j++){
            if(i == j)continue;
            if(check(x[i],y[i],x[j],y[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
            if(check(y[i],x[i],x[j],y[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
            if(check(x[i],y[i],y[j],x[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
            if(check(y[i],x[i],y[j],x[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

D:

题意:

给你n个数,选k个数相乘使得结果的后缀0最多

题解:

幼儿园大班芝士可知后缀0由质因子中的2和5决定
于是乎定义 d p i , j , k dp_{i,j,k} dpi,j,k 表示取到第 i i i 个数,已经取了 j j j 个数, 5 5 5 的质因子有 k k k 个时 2 2 2 的质因子最大值
然后 d p i , j , k dp_{i,j,k} dpi,j,k = m i n ( d p i − 1 , j , k , d p i − 1 , j − 1 , k − c n t 5 i + c n t 2 i ) min(dp_{i-1,j,k},dp_{i-1,j-1,k-cnt5_i}+cnt2_i) min(dpi1,j,k,dpi1,j1,kcnt5i+cnt2i)
初始条件 d p 0 , 0 , 0 = 0 dp_{0,0,0}=0 dp0,0,0=0 其余为 − I N F -INF INF
然后显然发现这个是01背包可以把i维度优化掉
然后就没有然后了

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 210;
int n, k;int a[maxn], b[maxn];
int dp[maxn][12810];//dp[i][j][k] = 当前到第i个数,选了j个数,5的因数为k个时2的因数最大值
signed main(){
    n = read();k = read();int x = 0;
    for(int i = 1;i <= n;i++){
        x = read();if(!x)continue;
        while(x % 2 == 0){a[i]++;x /= 2;}
        while(x % 5 == 0){b[i]++;x /= 5;}
    }
    memset(dp,~0x3f,sizeof(dp)); dp[0][0] = 0;
    for(int i = 1;i <= n;i++)
        for(int j = k;j >= 1;j--)
            for(int l = 12800;l >= b[i];l--)
                dp[j][l] = max(dp[j][l],dp[j - 1][l - b[i]] + a[i]);
    int ans = 0;
    for(int i = 0;i <= 12800;i++){ans = max(ans,min(i,dp[k][i]));}
    printf("%lld\n",ans);
    return 0;
}

E:

题意:

定义一个函数
f ( n , m ) = { 0 ,    ( m = 0 ) 1 + f ( n , m − g c d ( n , m ) ) ,    ( m ≠ 0 ) f(n,m) = \begin{cases} 0,\,\,(m=0)\\ 1+f(n,m-gcd(n,m)),\,\,(m\neq0)\\ \end{cases} f(n,m)={0,(m=0)1+f(n,mgcd(n,m)),(m=0)
然后给出 n n n m m m,求 f ( n , m ) f(n,m) f(n,m)

题解:

首先有一个推论 f ( n , m ) = f ( n g c d ( n , m ) , m g c d ( n , m ) ) f(n,m)=f(\frac{n}{gcd(n,m)},\frac{m}{gcd(n,m)}) f(n,m)=f(gcd(n,m)n,gcd(n,m)m)
然后问题就变成了每次求最大的 x < = m x<=m x<=m使得 x ∣ n x|n xn然后 f ( n , m ) = x + f ( n , x ) f(n,m)=x+f(n,x) f(n,m)=x+f(n,x)
这个好办,只需要把n的质因数都找出来( O ( log ⁡ 2 n ) ) O(\log_2n)) O(log2n))
然后每次更新时只需要暴力枚举找到 m a x ( m max(m max(m% i ) i) i),然后x就是前面的max值

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a, b;
const int maxn = 1e6 + 10;
bool book[maxn];int prime[maxn], cnt;
int x[maxn], p[maxn], tot;
int gcd(int x,int y){return y == 0 ? x : gcd(y,x % y);}
int f(int n,int m){
    int ans = 0;
    while(1){
        int mx = 0, pos = 0;
        for(int i = 1;i <= tot && x[i] <= m;i++)
            if(p[i] && (m / x[i] * x[i] > mx))mx = m / x[i] * x[i], pos = i;
        ans += m - mx;m = mx;
        if(!m)return ans;
        // if(m == 1){return ans + 1;}
        --p[pos];n /= x[pos]; m /= x[pos];
    }
    return -114514;
}
signed main(){
    scanf("%lld%lld",&a,&b);
    // book[1] = 1;int g = gcd(a, b);a /= g;b /= g;

    for(int i = 2;i <= 1e6;i++){
        if(!book[i]){prime[++cnt] = i;}
        for(int j = 1;j <= cnt && i * prime[j] <= 1e6;j++){
            book[i * prime[j]] = 1;
            if(i % prime[j] == 0)break;
        }
    }
    // for(int i = 1;i <= 10;i++)printf("prime[%lld] = %lld\n",i,prime[i]);
    int tmp = a;
    // tot++;x[tot] = 1;p[tot] = 1e18;
    for(int i = 1;i <= cnt && tmp >= prime[i];i++){
        if(tmp % prime[i] == 0){
            tot++;x[tot] = prime[i];while(tmp % prime[i] == 0){tmp /= prime[i];p[tot]++;}
        }
    }
    if(tmp != 1){tot++;x[tot] = tmp;p[tot] = 1;}
    // printf("%lld\n",tot);
    // for(int i = 1;i <= tot;i++)printf("x[%lld] = %lld,p[%lld] = %lld\n",i,x[i],i,p[i]);
    
    printf("%lld\n",f(a,b));

    return 0;
}

F:

题意:

给一个数组 a a a,每次操作让新的 a i a_i ai赋值为原来的 ∑ j = 1 i a j \sum_{j=1}^{i}a_j j=1iaj,问最少多少次操作使得 ∃ i , a i > = k \exist i,a_i>=k i,ai>=k

题解:

首先对于 n = = 2 n==2 n==2的情况可以 O ( 1 ) O(1) O(1)的计算答案(手推一下柿子就好了),对于 n > 10 n>10 n>10的情况可以暴力计算次数(由题解得最多计算410次),而对于 2 < n < = 10 2<n<=10 2<n<=10的情况可以用二分答案+矩阵快速幂

细节:

  • 原数组中的前导零无意义,直接删除
  • 乘法需要用龟速乘并且大于 k k k的数字没有乘的必要直接等于 k k k即可

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f= 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 2e5 + 10;
int n, k;
int a[maxn], tmp[maxn];
inline int mul(int a,int b){
    int res = 0;
    while(b){
        if(b & 1)res = res + a;
        if(res > k)return k;
        a = a + a;b >>= 1;a = min(k, a);
    }
    return res;
}
struct Matrix{
    int a[11][11];
    Matrix(){memset(a,0,sizeof(a));}
    friend Matrix operator * (Matrix a,Matrix b){
        Matrix ans;
        for(int i = 1;i <= n;i++)
            for(int t = 1;t <= n;t++)
                for(int j = 1;j <= n;j++){
                    ans.a[i][j] += mul(a.a[i][t] , b.a[t][j]);
                    if(ans.a[i][j] > k)ans.a[i][j] = k;
                }
        return ans;
    }
}A, B;
Matrix qpow(Matrix a,int x){
    Matrix res = a;x--;
    while(x){
        if(x & 1){res = res * a;}
        a = a * a;x >>= 1;
        // printf("x=  %lld\n",x);
    }
    return res;
}
bool check(int mid){
    Matrix res = A * qpow(B,mid);
    // puts("1111111111");
    for(int i = 1;i <= n;i++){if(res.a[1][i] >= k)return true;}
    return false;
}
signed main(){
    // #ifndef ONLINE_JUDGE
    // freopen("CF837F.in","r",stdin);
    // #endif
    n = read(); k = read();
    for(int i = 1;i <= n;i++)a[i] = read();
    int pos1 = 0, j = 1, book = 1;
    for(int i = 1;i <= n;i++){if(a[i] >= k){puts("0");return 0;}if(!a[i] && book)pos1 = i;else book = 0;}
    for(int i = pos1 + 1;i <= n;i++,j++){tmp[j] = a[i];}j--;
    for(int i = 1;i <= j;i++)a[i] = tmp[i];n = j;
    // printf("%lld\n",n);
    // for(int i = 1;i <= n;i++){printf("%lld ",a[i]);}
    if(n > 10){
        int cnt = 0;
        while(1){
            tmp[0] = 0;cnt++;
            for(int i = 1;i <= n;i++)tmp[i] = tmp[i - 1] + a[i];
            for(int i = 1;i <= n;i++){
                a[i] = tmp[i];
                if(a[i] >= k){printf("%lld\n",cnt);return 0;}
            }
        }
    }
    else if(n == 2){
        // if(a[2] >= k || a[1] >= k){puts("0");return 0;}
        int ans = (k - a[2]) / a[1] - 3;
        while(1){//精度修正
            if(ans * a[1] + a[2] >= k){printf("%lld\n",ans);return 0;}
            ans++;
        }
    }
    else{
        for(int i = 1;i <= n;i++){A.a[1][i] = a[i];}
        for(int i = 1;i <= n;i++)
            for(int j = n;j >= i;j--)
                B.a[i][j] = 1;
        int l = 1, r = 64356879284, mid = 0, ans = -1;
        // printf("n = %lld",n);
        while(l <= r){
            // printf("l=%lld r=%lld\n",l,r);
            mid = (r - l) / 2 + l;
            // printf("mid=%lld\n",mid);
            if(check(mid)){ans = mid;r = mid - 1;}
            else l = mid + 1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

G:

题意:

给出n个分段函数形如
f i ( x ) = { y 1 ,    ( x < = x 1 ) a ∗ x + b ,    ( x 1 < x < = x 2 ) y 2 ,    ( x > x 2 ) f_i(x)={ \begin{cases} y_1,\,\,(x<=x_1)\\ a*x+b,\,\,(x_1<x<=x_2)\\ y_2,\,\,(x>x_2) \end{cases} } fi(x)= y1,(x<=x1)ax+b,(x1<x<=x2)y2,(x>x2)
现在给出 l , r , x l,r,x l,r,x,求 ∑ i = l r f i ( x ) \sum_{i=l}^rf_i(x) i=lrfi(x),强制在线

题解:

首先先将原函数看作以下形式
f i ( x ) = { 0 ∗ x + y 1 ,    ( x < = x 1 ) a ∗ x + b ,    ( x 1 < x < = x 2 ) 0 ∗ x + y 2 ,    ( x > x 2 ) f_i(x)={ \begin{cases} 0*x+y_1,\,\,(x<=x_1)\\ a*x+b,\,\,(x_1<x<=x_2)\\ 0*x+y_2,\,\,(x>x_2) \end{cases} } fi(x)= 0x+y1,(x<=x1)ax+b,(x1<x<=x2)0x+y2,(x>x2)
然后将所求柿子转化一下
∑ i = l r f i ( x ) = ∑ i = l r a i ∗ x + ∑ i = l r b i \sum_{i=l}^rf_i(x)=\sum_{i=l}^ra_i*x+\sum_{i=l}^rb_i i=lrfi(x)=i=lraix+i=lrbi
  \space     \space     \space     \space     \space     \space     \space     \space     \space     \space   = ∑ i = 1 r a i ∗ x + ∑ i = 1 r b i − ∑ i = 1 l − 1 a i ∗ x + ∑ i = 1 l − 1 b i =\sum_{i=1}^ra_i*x+\sum_{i=1}^rb_i-\sum_{i=1}^{l-1}a_i*x+\sum_{i=1}^{l-1}b_i =i=1raix+i=1rbii=1l1aix+i=1l1bi
然后发现这玩应似乎可以可持久化主席树
然后就没啥了(那你还调了一下午)\

细节:

  • 线段树数组范围能开多大就多大(反正内存限制接近1GB)

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
    return x * f;
}
const int maxn = 75100, mod = 1e9;
int n, m;
int a[maxn][3], b[maxn][3], x[maxn][2];
struct Segment_Tree{
    struct node{
        int l, r;int a, b;
        node(int a = 0,int b = 0,int l = 0,int r = 0):a(a),b(b),l(l),r(r){}
    }d[maxn * 160];
    int tot;
    int newnode(int p){d[++tot] = d[p];return tot;}
    void update(int &p,int l,int r,int s,int t,int a,int  b){
        p = newnode(p);
        if(s <= l && r <= t){d[p].a += a;d[p].b += b;return;}
        int mid = l + r >> 1;
        if(s <= mid)update(d[p].l,l,mid,s,t,a,b);
        if(mid < t)update(d[p].r,mid + 1,r,s,t,a,b);
    }
    int query(int p,int l,int r,int x){
        if(!p)return 0;
        int res = x * d[p].a + d[p].b;
        if(l == r)return res;
        int mid = l + r >> 1;
        if(x <= mid)res += query(d[p].l,l,mid,x);
        else res += query(d[p].r,mid + 1,r,x);
        return res;
    }
}tree;
int head[maxn << 2], sum[maxn];
signed main(){
    n = read();int mx = 0;
    for(int i = 1;i <= n;i++){
        x[i][0] = read();x[i][1] = read();b[i][0] = read();
        a[i][1] = read();b[i][1] = read();b[i][2] = read();
        head[i] = head[i - 1];
        tree.update(head[i],0,mod,0          ,x[i][0],a[i][0],b[i][0]);
        tree.update(head[i],0,mod,x[i][0] + 1,x[i][1],a[i][1],b[i][1]);
        tree.update(head[i],0,mod,x[i][1] + 1,mod    ,a[i][2],b[i][2]);
        sum[i] = sum[i - 1] + b[i][2];mx = max(mx,x[i][1] + 1);
    }
    m = read();int lastans = 0;
    for(int i = 1;i <= m;i++){
        int l = read(), r = read(), pos = (read() + lastans) % mod;
        if(pos >= mx)printf("%lld\n",lastans = sum[r] - sum[l - 1]);
        else printf("%lld\n",lastans = tree.query(head[r],0,mod,pos) - tree.query(head[l - 1],0,mod,pos));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值