CF603题解
CF603
CF603A
CF603A题意
现有一个长度为 \(n\) 的 01 串, 可以进行一次区间翻转 ( 起点终点随意, 并且区间里的值 1 变 0, 0 变 1 ), 得到一个新的 01 串, 使得得到的新的 01 串中的一个子串最长 (子串不一定连续), 且这个子串是 01 间隔的,没有连续两个字符相同。比如 0101 , 101 和1010 是合法的, 100, 1100 是不合法的。试求翻转后最长 01 间隔子串的长度。
CF603A题解
设 \(f_{i,0/1/2}\) 分别表示 \(i\) 没有反转,\(i\) 前面没有反转区间 / \(i\) 没有反转,\(i\) 前面有反转区间 / \(i\) 反转,\(i\) 前面有反转区间 的情况下最长 \(01\) 子串。
那么显然有
没了。
CF603A代码
#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 = 1e5 + 10;
int n;
char ch[maxn];
int f[maxn][3];
signed main(){
n = read();scanf("%s",ch + 1);
int ans = 1;
f[1][0] = f[1][1] = f[1][2] = 1;
for(int i = 2;i <= n;i++){
f[i][0] = f[i - 1][0] + (ch[i] != ch[i - 1]);
f[i][1] = max(f[i - 1][1 + (ch[i] == ch[i - 1])] + 1,f[i - 1][1 + (ch[i] != ch[i - 1])]);
f[i][2] = max(f[i - 1][2] + (ch[i] != ch[i - 1]),f[i - 1][0] + (ch[i] == ch[i - 1]));
ans = max(max(ans,f[i][0]),max(f[i][1],f[i][2]));
}
printf("%d\n",ans);
return 0;
}
CF603B
CF603B题意
已知:\(f(k\times x\mod p)==k\times f(x)\mod p\)
对于一个从 \(f\{0,1,2,\dots,p-1\}\to\{0,1,2,\dots,p-1\}\) 的映射,问
对于给定的p和k,有多少种满足已知等式的映射
答案对 \(10^9+7\) 取模。
CF603B题解
下文中设 \(g(x)=k\times x \mod p\)。
\(k=0\) 时,\(\forall x\in[0,p-1],g(x)=0\),所以除了 \(f(0)=0\) 之外,剩下的随便,答案是 \(p^{p-1}\)。
\(k=1\) 时,\(\forall x\in[0,p-1],g(x)=x\),所以随便映射,答案是 \(p^{p}\)。
考虑完两种特殊情况之后,我们找到最小的正整数 \(m\),使得 \(k^m\equiv 1\pmod p\)。
不难发现,这个 \(m\) 将 \([1,p-1]\) 分成了 \(\frac{p-1}{m}\) 个环,这些环可以互相映射,答案是 \(p^{\frac{p-1}{m}}\)。
没了。
sbEric高一都学什么了
CF603B代码
#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 = 1e5 + 10, mod = 1e9 + 7;
int p, k;
int qpow(int x,int a){
int res = 1;
while(a){
if(a & 1)res = res * x % mod;
x = x * x % mod;a >>= 1;
}
return res;
}
signed main(){
p = read(); k = read();
if(k == 0){printf("%lld\n",qpow(p,p - 1));return 0;}
if(k == 1){printf("%lld\n",qpow(p,p));return 0;}
int m = 1,tmp = k;while(tmp != 1){tmp = tmp * k % p;m++;}
printf("%lld\n",qpow(p,(p - 1) / m));
return 0;
}
CF603C
CF603C题意
有两个人做游戏,游戏规则如下:
有n堆石子,每次可以对一堆石子进行操作,如果当前石子是偶数,那么可以选择将这2*x个石子分成k堆石子数为x的石子堆,还有一种没有前提的操作是取走当前堆的一个石子,问先手赢还是后手赢,先手和后手都足够聪明的情况下。
先手赢输出Kevin,后手赢输出Nicky
CF603C题解
尝试设定SG函数。
\(0\) 到 \(4\) 的SG函数是可以手算的。
现在需要算 \(SG(x),x\ge 5\)。
考虑对于 \(k\) 和 \(x\) 的奇偶性分类讨论。
- \(k\) 是奇数,\(x\) 是奇数:\(SG(x)=mex\{SG(x-1)\}=0\)。
- \(k\) 是奇数,\(x\) 是偶数:\(SG(x)=mex\{SG(\frac{x}{2}),SG(x-1)\}=mex\{SG(\frac{x}{2}),0\}\),而 \(SG(\frac{x}{2})\) 进行递归计算,次数不会超过 \(\log x\) 次。
- \(k\) 是偶数,\(x\) 是偶数:\(SG(x)=mex\{SG(x-1),SG(\frac{x}{2}) \oplus SG(\frac{x}{2})=0\}=1\)。
- \(k\) 是偶数,\(x\) 是奇数:\(SG(x)=mex\{SG(x-1)\}=0\)。
没了。
CF603C代码
#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 = 1e5 + 10;
int n, k;
int SG(int x){
if(x <= 1)return x;
if(k % 2 == 1){
if(x <= 4)return x - 2;
if(x & 1)return 0;
return SG(x / 2) != 1 ? 1 : 2;
}
if(x == 2)return x;
return x % 2 == 0;
}
signed main(){
n = read(); k = read();int ans = 0;
for(int i = 1;i <= n;i++)ans ^= SG(read());
puts(ans ? "Kevin" : "Nicky");
return 0;
}
CF603D
CF603D题意
有 \(n\) 条直线,两两不平行,任意 \(3\) 条直线不经过同一个点。求三条直线 \(i,j,k\) 围成的三角形的外接圆过原点的三元无序点 \((i,j,k)\) 的数量。
\(n\le2000\)
CF603D题解
阅读前请确保你知道什么是Simson_line
对于每条线段都求出原点到这条直线的垂点。
然后这个问题就转化成为了求三点共线的无序点对 \((i,j,k)\) 的数量。
这东西想怎么求怎么求,反正 \(O(n^2)\sim O(n^2\log n)\) 都是可过的。
不过必须注意的是,这题TM卡double的精度,让 \(eps\gets 10^{-10}\) 的精度不够,需要 \(10^{-12}\),大了小了都不行。
CF603D代码
#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 = 2e3 + 10;
const double eps = 1e-12;
int a[maxn], b[maxn], c[maxn];
int n;
double x[maxn], y[maxn];
signed main(){
n = read();
for(int i = 1;i <= n;i++){
a[i] = read(); b[i] = read(); c[i] = read();
x[i] = 1.0 * c[i] * a[i] / (a[i] * a[i] * 1.0 + b[i] * b[i] * 1.0);
y[i] = 1.0 * c[i] * b[i] / (a[i] * a[i] * 1.0 + b[i] * b[i] * 1.0);
// printf("x = %lf, y = %lf\n",x[i],y[i]);
}
int ans = 0;
for(int i = 1;i <= n;i++){
int sam = 0,cnt = 0;vector<double> vec;vec.clear();
for(int j = 1;j <= n;j++){
if(j == i)continue;
double dx = x[j] - x[i];
double dy = y[j] - y[i];
if(abs(dx) < eps && abs(dy) < eps)sam++;
else if(abs(dx) < eps) cnt++;
else vec.push_back(dy / dx);
}
sort(vec.begin(),vec.end(),greater<double>());
int k = 0;
ans += (cnt - 1 + sam) * (cnt + sam);
for(int j = 0;j < vec.size();j += k, k = 1){
while(j + k < vec.size() && abs(vec[k + j] - vec[j]) < eps)k++;
ans += (k + sam) * (k + sam - 1);
// printf("j = %d k = %d\n",j,k);
}
// for(int j = 1;j < vec.size();j++)
// printf("j = %d,dirt = %lf\n",j,vec[j + 1] - vec[j]);
}
printf("%d\n",ans / 6);
return 0;
}
CF603E
CF603E题意
给定一张 \(n\) 个点的无向图,初始没有边。
依次加入 \(m\) 条带权的边,每次加入后询问是否存在一个边集,满足每个点的度数均为奇数。
若存在,则还需要最小化边集中的最大边权。
\(n \le 10^5\),\(m \le 3 \times 10^5\)。
CF603E题解
首先想想这个条件:要求每个点的度数都是奇数。
其实这个限制已经很强了:
- 对于一个成立的图,一定不能有一个大小为奇数的联通块。
- 简单证明:每加入一条边,都会改变两个点的度数奇偶性,最开始每个点都是偶数的度数,奇数个点显然不能全都改变成奇数的度数。
- 那联通块大小是偶数就一定都成立吗?
- 一定,你先搞一个联通块的任意生成树,然后从下向上,一旦有的点度数不是奇数,那么就删除向 \(fa_u\) 连接的边,这样的话,只有根有可能是不满足的。
- 但是显然是满足的,如果不满足,那么整个联通块的度数之和就是奇数,显然不可能出现这种情况。
于是问题就变成了,每次加入一条边,要求你选择一些边,使得所有的联通块都是偶数的大小,并且希望连接的边最大值最小。
不难联想到Kruskal最小瓶颈生成树。
想到线段树分治,从右向左维护答案。
于是问题就变成了,一条边在哪个时间段会有贡献。
我们知道,如果有一条边在某一时刻没有被选择加入最小生成树,那么任意时刻都不会再选择它了。
于是维护Kruskal加入边时的指针,每次更新直到满足条件或者没有边可用。
然后如果一条边被加入,那么就在 \([id,l - 1]\) 这个时间段加入这条边即可。
CF603E代码
#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 = 1e5 + 10, maxm = 3e5 + 10;
int n, m;
struct edge{
int fr, to ,wei, id;
edge(int fr = 0,int to = 0,int wei = 0,int id = 0):fr(fr),to(to),wei(wei),id(id){}
friend bool operator < ( edge a,edge b){return a.wei < b.wei;}
}e[maxm];
struct mystk{
struct node{
int x, y, dep, updodd, siz;
node(int x = 0,int y = 0,int dep = 0,int siz = 0,int updodd = 0):x(x),y(y),dep(dep),updodd(updodd),siz(siz){}
};
node st[maxm];
int op;
void pop(){op--;}
node top(){return st[op];}
void push(node x){st[++op] = x;}
bool empty(){return op == 0;}
};
struct DSU{
mystk stk;
int oddblock;
int fa[maxn], dep[maxn], siz[maxn];
void init(int x = 0){oddblock = x;for(int i = 1;i <= x;i++){fa[i] = i;dep[i] = siz[i] = 1;}}
int getf(int x){return fa[x] == x ? x : getf(fa[x]);}
void merge(int x,int y){
int fx = getf(x), fy = getf(y);
// printf("getf(%d) = %d,getf(%d) = %d\n",x,fx,y,fy);
if(fx == fy)return;
// printf("merged %d, %d\n",x,y);
if(dep[fx] > dep[fy])swap(fx,fy);
stk.push(mystk::node(fx,fy,dep[fx] == dep[fy],siz[fx],((siz[fx] + siz[fy]) % 2 == 1) - ((siz[fx] % 2 == 1) + (siz[fy] % 2 == 1))));
oddblock += (((siz[fx] + siz[fy]) % 2 == 1) - ((siz[fx] % 2 == 1) + (siz[fy] % 2 == 1)));
fa[fx] = fy;dep[fy] += (dep[fx] == dep[fy]); siz[fy] += siz[fx];
}
void trace(int rev = -1){
while(rev < stk.op){
// printf("top = %d,rev= %d\n",stk.op,rev);
int x = stk.top().x, y = stk.top().y, dept = stk.top().dep, sz = stk.top().siz, updodd = stk.top().updodd;
fa[x] = x;dep[y] -= dept;siz[x] = sz;siz[y] -= sz;oddblock -= updodd; stk.pop();
}
}
}dsu;
int pos, ans[maxm];
struct Segment_Tree{
vector<int> d[maxm << 2];
void update(int l,int r,int s,int t,int p,int id){
if(s <= l && r <= t){d[p].push_back(id);return;}
int mid = l + r >> 1;
if(s <= mid)update(l,mid,s,t,p << 1,id);
if(mid < t)update(mid + 1,r,s,t,p << 1 | 1,id);
}
void update(int s,int t,int id){update(1,m,s,t,1,id);}
void query(int l,int r,int p){
int ver = dsu.stk.op;
for(int i : d[p])dsu.merge(e[i].fr,e[i].to);
int mid = l + r >> 1;
if(l == r){
while(dsu.oddblock != 0 && pos < m){
pos++;
// printf("in rev = %d, l = %d, pos = %d\n",ver, l, pos);
// printf("u = %d v = %d w = %d\n",e[pos].fr,e[pos].to,e[pos].wei);
if(e[pos].id <= l){
dsu.merge(e[pos].fr,e[pos].to);
if(l != 1) update(e[pos].id,l - 1,pos);
}
// printf("odd = %d\n",dsu.oddblock);
}
if(dsu.oddblock == 0)ans[l] = e[pos].wei;
else ans[l] = -1;
}
else {query(mid + 1,r,p << 1 | 1);query(l,mid,p << 1);}
dsu.trace(ver);
}
}tree;
signed main(){
n = read(); m = read();int u, v, w;
if(n & 1){for(int i = 1;i <= m;i++)puts("-1");return 0;}
for(int i = 1;i <= m;i++){
u = read(); v= read(); w = read();
e[i] = edge(u, v, w, i);
}
sort(e + 1,e + 1 + m);dsu.init(n); tree.query(1, m, 1);
for(int i = 1;i <= m;i++)printf("%d\n",ans[i]);
return 0;
}

浙公网安备 33010602011771号