20230704测试
H
新外号:
这题就有点一眼了,vector
,维护前缀和后缀的整体
好吧,其实可以增量构造,维护一个双指针,由于后面的
这里很懒,用了
const int maxN=1e5+10;
inline int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
int idx=1,n,m,root=1;
struct node {
vector<pii> lgc,rgc;
ll res=0;
}seg[maxN<<1];
int son[maxN<<1][2];
int a[maxN];
node pushup(node x,node y){
ll res=0;
for(pii z:x.rgc)
for(pii w:y.lgc)
if(gcd(z.fir,w.fir)!=1)
res+=z.sec*w.sec;
res+=x.res+y.res;
int last=y.rgc.back().first;
for(pii z:x.rgc){
int g=gcd(last,z.fir);
if(g==last) y.rgc.back().sec+=z.sec;
else{
last=g;
y.rgc.push_back({g,z.sec});
}
}
last=x.lgc.back().first;
for(pii z:y.lgc){
int g=gcd(last,z.fir);
if(g==last) x.lgc.back().sec+=z.sec;
else {
last=g;
x.lgc.push_back({g,z.sec});
}
}
node temp;
temp.lgc=x.lgc;
temp.rgc=y.rgc;
temp.res=res;
return temp;
}
void Clear(int now){
seg[now].rgc.clear();
seg[now].lgc.clear();
seg[now].res=0;
}
inline void build(int &now,int l,int r){
if(!now) now=++idx;
if(l==r){
seg[now].lgc.push_back({a[l],1});
seg[now].rgc.push_back({a[l],1});
if(a[l]!=1) seg[now].res=1;
return ;
}
int mid=(l+r)>>1;
build(son[now][0],l,mid);
build(son[now][1],mid+1,r);
seg[now]=pushup(seg[son[now][0]],seg[son[now][1]]);
}
inline void modify(int now,int l,int r,int wh){
if(l==r){
Clear(now);
seg[now].lgc.push_back({a[l],1});
seg[now].rgc.push_back({a[l],1});
if(a[l]!=1) seg[now].res=1;
return ;
}
int mid=(l+r)>>1;
if(wh<=mid) modify(son[now][0],l,mid,wh);
else modify(son[now][1],mid+1,r,wh);
seg[now]=pushup(seg[son[now][0]],seg[son[now][1]]);
}
inline node query(int now,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)
return seg[now];
int mid=(l+r)>>1;
if(qr<=mid) return query(son[now][0],l,mid,ql,qr);
else if(ql>mid) return query(son[now][1],mid+1,r,ql,qr);
else return pushup(query(son[now][0],l,mid,ql,qr),query(son[now][1],mid+1,r,ql,qr));
}
void solve(){
n=rd(),m=rd();
fp(i,1,n) a[i]=rd();
build(root,1,n);
while(m--){
int op=rd(),x=rd(),y=rd();
if(op==1) a[x]=y,modify(root,1,n,x);
else{
node p=query(1,1,n,x,y);
cout << p.res << endl;
}
}
}
G
计数,计数,计数!
加练,加练,加练!
这个加边就很灵性
这个定向就很二分图,不是定这个向,就是这个向
所以可以想到一个二分图的方法
对于规定的这两个点之间的边,他们的方向都是一样的,这里把边映射到点上,中间的点用二并查集连起来
同时发现,如果这条路线转了个弯,则劈出的链是不一样的
这里一个点所代表的边与其父亲边连在一起,要求有一个点能继续向上连
const int maxN=3*1e5+10;
int n,k;
vector<int> g[maxN];
int acc[maxN][25],dep[maxN];
int f[maxN<<1],h[maxN];
int findx(int x){
if(f[x]==x) return x;
return f[x]=findx(f[x]);
}
void merge(int x,int y){f[findx(x)]=findx(y);}
inline void dfs1(int now,int f){
acc[now][0]=f;
dep[now]=dep[f]+1;
for(int i=0,v=acc[now][i];v;v=acc[now][++i]) acc[now][i+1]=acc[v][i];
for(int x:g[now]) if(x!=f) dfs1(x,now);
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int gap=dep[x]-dep[y],bit=logx(gap);gap;gap-=(1<<bit),bit=logx(gap)) x=acc[x][bit];
for(int i=logx(dep[x]);~i;--i) if(acc[x][i]!=acc[y][i]) x=acc[x][i],y=acc[y][i];
return (x==y)?x:acc[x][0];
}
void dfs2(int now,int f){
for(int x:g[now]){
if(x==f) continue;
dfs2(x,now);
h[now]=min(h[now],h[x]);
}
if(h[now]<dep[now]-1){
merge(f,now);
merge(f+n,now+n);
}
}
int qmi(int p){
int ans=1,x=2;
for(;p;p>>=1){if(p&1) (ans*=x)%=mod;(x*=x)%=mod;}
return ans;
}
void solve(){
n=rd(),k=rd();
fp(i,1,n-1){
int u=rd(),v=rd();
g[u].push_back(v),g[v].push_back(u);
}
fp(i,1,n<<1) f[i]=i;
dfs1(1,0);
fp(i,1,n) h[i]=dep[i];
while(k--){
int a=rd(),b=rd();
int c=lca(a,b);
if(a==b) continue ;
h[a]=min(h[a],dep[c]);
h[b]=min(h[b],dep[c]);
if(c!=a&&c!=b) merge(a+n,b),merge(a,b+n);
}
dfs2(1,0);
int cnt=0;
fp(i,1,n)
if(findx(i)==findx(i+n)) {
cout << 0 << endl;
return ;
}
fp(i,1,n<<1){
if(i==findx(i))
++cnt;
}
cnt-=2;
cnt>>=1;
cout << qmi(cnt) << endl;
}
F
喵喵题
非常的怪啊,这个题就是一个奇妙贪心
一开始大家的思路可能就是让伤害多的先上场然后再换就可以了,但是这个思路会在第三个样例狗带
然后你可能会想,我让总攻击力最强的先上不久行了,但是这样就有可能打不满了,值无法维护
可以从另一个角度来解读这个条件,对于这个对战,可以抽象成一个方格,向着个方格里面来填数,hp
可以抽象成有多少个物品,这样的话,就优先向里面放价值大的物品就可以了,为了少换人,就横着填
因为题目的特殊限定,所以这样是对的
const int maxN = 5 * 1e5 + 10;
int m, n;
struct node {
int deg, hp, id;
} a[maxN];
int arr[7][maxN];
void solve() {
m = rd(), n = rd();
fp(i, 1, n) {
int x = rd(), y = rd(), z = i;
a[i] = { x, y, z };
}
sort(a + 1, a + n + 1, [&](node x, node y) { return x.deg > y.deg; });
int p = 1, thp = a[p].hp;
ll maxx = 0;
fp(k, 1, 6)
fp(j, 1, m) {
arr[k][j] = a[p].id, maxx += a[p].deg;
--thp;
if (!thp)
++p, thp = a[p].hp;
}
cout << maxx << endl;
ll op = 0;
set<int> st;
fp(i, 1, 6) st.insert(arr[i][1]);
fp(i, 2, m) {
vector<int> v;
set<int> st2;
fp(k, 1, 6) if (st.count(arr[k][i])) st.erase(arr[k][i]), st2.insert(arr[k][i]);
else v.push_back(arr[k][i]), st2.insert(arr[k][i]);
op += st.size();
swap(st2, st);
}
fp(i, 1, 6) cout << arr[i][1] << ' '; cout << endl;
cout << op << endl;
st.clear();
fp(i, 1, 6) st.insert(arr[i][1]);
fp(i, 2, m) {
vector<int> v;
set<int> st2;
fp(k, 1, 6) if (st.count(arr[k][i])) st.erase(arr[k][i]), st2.insert(arr[k][i]);
else v.push_back(arr[k][i]), st2.insert(arr[k][i]);
for (int x : st) cout << i - 1 << ' ' << x << ' ' << v.back() << endl, v.pop_back();
swap(st2, st);
}
}
E
明显有搜索的解法
然后折个半
最后统计答案的时候就lower_bound
一下就可以了
const int maxN = 100;
int n, lim1, lim2, k;
ll ans = 0;
pii a[maxN];
vector<pii> v1;
vector<int> v2[maxN];
void lis() {
vector<int> v;
fp(i, 1, n) v.push_back(a[i].fir);
sort(v.begin(), v.end());
int len = unique(v.begin(), v.end()) - v.begin();
while (v.size() != len) v.pop_back();
fp(i, 1, n) a[i].fir = lower_bound(v.begin(), v.end(), a[i].fir) - v.begin() + 1;
v.clear();
}
inline void dfs1(int now, ll sum) {
if (now)
v1.push_back({ sum, a[now].fir });
if (sum >= k)
++ans;
fp(i, now + 1, lim1) if (a[now].fir <= a[i].fir) dfs1(i, sum + a[i].sec);
}
inline void dfs2(int now, ll sum) {
if (now != n + 1)
v2[now].push_back(sum);
if (sum >= k)
++ans;
fd(i, now - 1, lim2) if (a[now].fir >= a[i].fir) dfs2(i, sum + a[i].sec);
}
void solve() {
n = rd(), k = rd();
fp(i, 1, n) a[i].fir = rd(), a[i].sec = rd();
a[0].fir = 0;
lis();
lim1 = n >> 1;
lim2 = lim1 + 1;
a[n + 1].fir = inf;
dfs1(0, 0);
dfs2(n + 1, 0);
fp(i, 1, n) sort(v2[i].begin(), v2[i].end());
fp(i, 1, v1.size()) {
auto temp = v1[i - 1];
fp(j, lim2, n) if (temp.sec <= a[j].fir) {
int t = lower_bound(v2[j].begin(), v2[j].end(), k - temp.fir) - v2[j].begin();
if (v2[j].empty())
continue;
if (v2[j].back() < k - temp.fir)
continue;
ans += v2[j].size() - t;
}
}
cout << ans << endl;
}
D
傻逼题,翻转的贡献最多只有
const int maxN = 5 * 1e5 + 10;
int n;
int a[maxN << 1], pos[maxN << 1], pre[maxN << 1];
vector<int> v[maxN << 1];
int dis(int x, int y) { return max(x, y) - min(x, y); }
int q(int l, int r) { return pre[r] - pre[l - 1]; }
void solve() {
n = rd();
fp(i, 1, n) a[(i << 1) - 1] = rd(), a[i << 1] = 0;
n *= 2;
fp(i, 1, n) if (a[i]) pos[a[i]] = i;
fp(i, 1, n >> 1) {
if (i * 2 - 1 != pos[i])
v[(i * 2 - 1 + pos[i]) >> 1].push_back(dis(i * 2 - 1, pos[i]) >> 1);
}
fp(i, 1, n) sort(v[i].begin(), v[i].end());
fp(i, 1, n) pre[i] = pre[i - 1] + ((a[i] * 2 - 1) == i);
int ans = 0;
fp(i, 1, n) {
int sum = 0;
for (int x : v[i]) {
++sum;
int tot = sum - q(i - x, i + x) + ((a[i] * 2 - 1) == i);
ans = max(tot, ans);
}
}
cout << ans << endl;
}
A-C
水省
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话