Codeforces Round 596 题解

万幸的是终于碰上了一场上分好场。

不幸的是一开始差点不会 A。

万幸的是想了个不那么稳的结论过了 pretest。

不幸的是罚时很高,而且慌得一比。

万幸的是然后半个小时内把 B 和 C 码了。

不幸的是然后就只能看着排名一点一点掉了。

万幸的是最后 A 没被叉掉。

不幸的是我居然没敢去叉人。

万幸的是我就是叉了 10 个人排名也不会上涨超过 5。

不幸的是我每掉一名都会少涨两三分。

万幸的是我没去打隔壁的 ZR。

不幸的是我发现这场 ZR 我一题不会,打了就会掉分……


2A

没仔细想,但是应该分类讨论一下 \(d_a=d_b\),\(d_a+1=d_b\) 和 \(d_a=9,d_b=1\) 就行了。

2B1 & 2B2

没仔细想,但是感觉双指针,动态维护不同数的个数(开个 map)就行了。

2C/1A

先枚举要用多少个数拼成 \(n\)。假设当前枚举的是 \(i\)。

那么等价于用恰好 \(i\) 个 \(2\) 的整数次幂拼成 \(n-pi\)。

有解当且仅当 \(bitcnt(n-pi)\le i\) 且 \(n-pi\ge i\)。其中 \(bitcnt\) 是二进制表示中 \(1\) 的个数。

我当时猜的结论是如果有解答案不会超过 \(10^6\)(能稳就稳)。

搬运下官方题解:

当 \(n-30p\ge 30\) 时(即 \(i=30\) 时满足第二个条件),那么因为 \(n-30p<2^{30}\),\(30\) 是一定合法的。否则对于 \(i\ge 30\),\(n-pi\ge i\) 都不可能成立。所以答案至多是 \(30\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=100010;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,p;
inline int bitcnt(int x){
    int c=0;
    for(;x;x&=x-1) c++;
    return c;
}
int main(){
    n=read();p=read();
    FOR(i,1,1000000){
        if(n-p*i>=i && bitcnt(n-p*i)<=i){
            printf("%d\n",i);return 0;
        }
    }
    puts("-1");
}

2D/1B

把每个数质因数分解。设 \(a_i=p_{i,1}^{c_{i,1}}\times p_{i,2}^{c_{i,2}}\times\dots\times p_{i,l_i}^{c_{i,l_i}}\)。其中 \(p_{i,x}\) 均为质数且单调递增,\(c_{i,x}\) 均为正整数。

两个数 \(i,j\) 合法当且仅当 \(l_i=l_j\) 且 \(p_{i,x}=p_{j,x}\) 且 \(k|(c_{i,x}+c_{j,x})\)。

那么把 \((p_{i,x},c_{i,x}\bmod k)\) 这个二元组塞到一个 vector 后面。并且查找要求的 vector 之前的出现次数。

时间复杂度 \(O(nl\log n)\)。其中 \(l\) 为 \(n\) 以内所有正整数的互不相同质因子个数的最大值。\(n=10^5\) 时,\(l=6\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=100010,sq=333;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,k,a[maxn];
vector<PII> d[maxn],tmp;
map<vector<PII>,int> cnt;
ll ans;
int main(){
    n=read();k=read();
    FOR(i,1,n) a[i]=read();
    FOR(i,1,n){
        int x=a[i];
        tmp.clear();
        FOR(j,2,sqrt(x)) if(x%j==0){
            int cnt=0;
            while(x%j==0) x/=j,cnt=(cnt+1)%k;
            if(cnt) d[i].push_back(MP(j,cnt)),tmp.push_back(MP(j,k-cnt));
        }
        if(x>1) d[i].push_back(MP(x,1)),tmp.push_back(MP(x,k-1));
        ans+=cnt[tmp];
        cnt[d[i]]++;
    }
    printf("%lld\n",ans);
}

2E/1C

比较套路的一题。

令 \(f_{i,j,0}\) 表示目前在 \((i,j)\),上一步是从左边走过来的方案数。\(f_{i,j,1}\) 表示目前在 \((i,j)\),上一步是从上面走过来的方案数。

初始状态 \(f_{1,1,0}=f_{1,1,1}=1\)。答案是 \(f_{n,m,0}+f_{n,m,1}\)。(所以要特判 \(n=m=1\),至于初始状态为什么是这个,看到下面就知道了)

以 \(f_{i,j,0}\) 为例,枚举上一个是从上面走过来的点 \((i,k)\)。注意到 \((i,k)\) 右边的石头肯定之前都没被动过。

那么从 \((i,k)\) 走到 \((i,j)\) 当且仅当 \((i,k)\) 右边的石头个数 \(\le n-j\)。这样子这些石头都可以塞到 \((i,j)\) 右边,否则 \((i,j)\) 肯定被石头挡住。

如果这样,\(f_{i,j,0}+=f_{i,k,1}\)。

发现 \(k\) 一定是 \([l,j-1]\) 这么一段,可以二分 \(l\) 然后用前缀和优化。当然发现随着 \(j\) 递增,\(l\) 不会变小,也可以维护一个指针。我比较懒就用了二分。

时间复杂度 \(O(nm(\log n+\log m))\) 或者 \(O(nm)\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=2222,mod=1000000007;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,m,f[maxn][maxn][2],rig[maxn][maxn],dn[maxn][maxn],sum1[maxn][maxn],sum2[maxn][maxn];
char mp[maxn];
bool bl[maxn][maxn];
int main(){
    n=read();m=read();
    if(n==1 && m==1) return puts("1"),0;
    FOR(i,1,n){
        scanf("%s",mp+1);
        FOR(j,1,m) if(mp[j]=='R') bl[i][j]=true;
    }
    f[1][1][0]=f[1][1][1]=sum1[1][1]=sum2[1][1]=1;
    FOR(i,1,n) ROF(j,m,1) rig[i][j]=rig[i][j+1]+bl[i][j+1];
    ROF(i,n,1) FOR(j,1,m) dn[i][j]=dn[i+1][j]+bl[i+1][j];
    FOR(i,1,n) FOR(j,1,m){
        if(i==1 && j==1) continue;
        int l=0,r=j;
        while(l<r){
            int mid=(l+r)>>1;
            if(rig[i][mid]<=m-j) r=mid;
            else l=mid+1;
        }
        if(l<j) f[i][j][0]=(f[i][j][0]+(sum1[i][j-1]-(l==0?0:sum1[i][l-1])+mod)%mod)%mod;
        l=0;r=i;
        while(l<r){
            int mid=(l+r)>>1;
            if(dn[mid][j]<=n-i) r=mid;
            else l=mid+1;
        }
        if(l<i) f[i][j][1]=(f[i][j][1]+(sum2[i-1][j]-(l==0?0:sum2[l-1][j])+mod)%mod)%mod;
        sum1[i][j]=(sum1[i][j-1]+f[i][j][1])%mod;
        sum2[i][j]=(sum2[i-1][j]+f[i][j][0])%mod;
//      printf("f[%d][%d]=%d\n",i,j,(f[i][j][0]+f[i][j][1])%mod);
    }
    printf("%d\n",(f[n][m][0]+f[n][m][1])%mod);
}

2F/1D & 1E & 1F

这些都不会,咕了。

原文地址:https://www.cnblogs.com/1000Suns/p/11746670.html

时间: 2024-10-08 20:43:45

Codeforces Round 596 题解的相关文章

Codeforces Round #541 题解

codeforces Round #541 C 题意 给你100个人,让你将它们围成一个圆,使得:"任意相邻的两人身高差的绝对值" 中的最大值 最小 题解 显然的构造方法:先排序,让所有人1 2 报数,报2的出列,排尾变排头接到报 1 的原队列后面 证明: 显然这样的构造方法保证身高差最大为 max{(a[i+2]-a[i]) }(i=1..n,环状,a[i]升序): 我们可以说明对于任意的i,身高差至少为(a[i+2]-a[i]), 如果我们将每个人看成一个点,相邻关系看成一条无向边

CFEducational Codeforces Round 66题解报告

CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第\(k\)小的值 那么问题就变成了 每一个数变成了\([x-mid,x+mid]\)的一段区间,如果有一个位置被覆盖了超过\(k\)次 那么\(mid\)一定合法 类似括号匹配 每次碰到左端点就贡献+1 右端点就统计答案然后-1 维护答案的同时顺便维护位置就好了 #include<cstdio>

codeforces Round#332Div2 题解

codeforces Round#332Div2 AB 签到题 比较激动,纷纷WA了一发. C 把数组h复制给a,然后对a数组排序. 对h和a数组,求前缀和,有多少个位置满足\(\sum a[i] = \sum h[i]\), 就最多能分成多少块. D 我们枚举更短的那条边,这样的边不会太多. 然后求,更长的那条边. E 符合xxx限定条件的图的计数问题.数据范围很状压. 我们用dp[mask][root]表示,集合mask里的点,以root为根,不违背限定条件的方案数. 接下来考虑dp[mas

Codeforces Round #596 Div1 A~E题解

我好菜啊 A 题意: 定义p-二进制数为2^k-p,给出n和p,求用最小个数的p-二进制数来表示n 1<=n<=10^9,-1000<=p<=1000 题解: 猜结论,答案不会很大 n可以表示成kp+s的形式,枚举k,判断(n-kp)是否能用k个2的幂构成 画一下图可以发现,如果可以构成,那么满足(n-kp)的位数<=k<=n-kp (相当于把一颗二叉树上一个点变成两个) 证明答案不会很大: 首先(n-kp)的位数最多为30 ①p>=0 显然当k超过30后,如果不

Codeforces Educational Codeforces Round 54 题解

题目链接:https://codeforc.es/contest/1076 A. Minimizing the String 题意:给出一个字符串,最多删掉一个字母,输出操作后字典序最小的字符串. 题解:若存在一个位置 i 满足 a[i] > a[i+1],若不删除 a[i] 则后续操作不可能更优. 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned

Educational Codeforces Round 55 题解

题解 CF1082A [Vasya and Book] 史上最难A题,没有之一 从题意可以看出,翻到目标页只有三种办法 先从\(x\)到\(1\),再从\(1\)到\(y\) 先从\(x\)到\(n\),再从\(n\)到\(y\) 直接从\(x\)到\(y\) 三种的必要条件分别是 \((y-1)\mod d \equiv 0\) \((n-y)\mod d \equiv 0\) \(|x-y|\mod d \equiv 0\) 所以如果上面三种都不满足的话就输出\(-1\) 不然就取最小的输出

Codeforces Round #616 题解

A题 我们注意到如果存在两个奇数,那么就能满足题目条件,所以我们就从头寻找两个奇数,没有的话就是无解 #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> using namespace st

Codeforces Educational Codeforces Round 57 题解

传送门 Div 2的比赛,前四题还有那么多人过,应该是SB题,就不讲了. 这场比赛一堆计数题,很舒服.(虽然我没打) E. The Top Scorer 其实这题也不难,不知道为什么这么少人过. 考虑枚举那人的分数和有多少人和他同分,推一下就会发现我们只需要知道\(calc(sum,n,top)\)表示\(sum\)分,分给\(n\)个人,分数小于\(top\),的方案数. 好像不是很好直接搞,考虑容斥,枚举一下至少有几个人不满足条件即可. #include<bits/stdc++.h> na

Codeforces Round 564 题解

很抱歉让标题把您骗进来了. 这是一场打得最失败的div1. 作为一个橙名一题都不会…… 旁边紫名的PB怒切3题,div2的也随便玩玩出了div1b/div2d…… 这名字颜色也太有水分了. 也就只会2A和2B了,写一写吧. 2A 水题.代码咕,也会一直咕下去. 2B 简单构造. 首先发现 $|r_1-r_n|+|c_1-c_n|\ge n-1$.那么令 $r_1=c_1=1,r_n=\lfloor\frac{n}{2}\rfloor,c_n=\lceil\frac{n}{2}\rceil$ 时