Codeforces Round 895 (Div. 3)

A.每次最多能把差缩小2*c克,向上取整

#include 
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
using node=tuple;
typedef long long LL;
typedef pair PII;

int n,m,q;
int a[N];
void solve()
{
     int a,b,c;cin>>a>>b>>c;
     cout<<(abs(a-b)+2*c-1)/(2*c)<<"\n";
}
signed  main() {
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
    
}

B.直接枚举每个格子能走多大

#include 
using namespace std;
const int N = 2e5+10,M=2*N,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
int a[N],b[N];
int n, m;

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
    }
    int mx=1000000,mn=0;
    for(int i=1;i<=n;i++)
    {
        mx=min(mx,a[i]+((b[i]-1)/2));
    }
    cout<>t;
    while(t--) solve();
    
}

C.首先容易构造的是gcd=2,相当于是一个偶数/2,那么这种情况要特判

l==r,只能找他的质因子了,

#include 
using namespace std;
const int N = 2e5+10,M=2*N,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
int a[N],b[N];
int n, m;

void solve()
{
    int l,r;cin>>l>>r;
    if(l==r)
    {
        for(int i=2;i<=l/i;i++){
            if(l%i==0){
                int x=l/i;
                cout<>t;
    while(t--) solve();
    
}

D.容斥原理

a+b-a*b,特判另一个数包含另一个数的集合就行

#include 
using namespace std;
const int N = 2e5+10,M=2*N,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
int a[N],b[N];
int n, m;
int gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
void solve()
{
    cin>>n;
    int x,y;cin>>x>>y;

    if(x%y==0)
    {   int z=n/y-n/x;
        cout<<-((z+1)*z)/2<<"\n";
    }
    else if(y%x==0)
    {
        int z=n/x-n/y;
        cout<<((n-z+1+n)*z)/2<<"\n";
    }
    else if(x!=1&&y!=1&&x!=y){
        int now=n/(lcm(x,y));
        int z=n/x-now;
        int res=(n-z+1+n)*z/2;
        z=n/y-now;

        res-=((z+1)*z)/2;
        cout<>t;
    while(t--) solve();
    
}

E.直接线段树维护区间0的异或和 和 1的异或和,翻转操作就是互换而已

#include 
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
struct node{
    int l,r;
    int s0,s1,w,add;
}tr[N*4];
int n,m,q;
int a[N],b[N];
string s;
void pushup(int u){
    tr[u].s0=tr[u<<1].s0^tr[u<<1|1].s0;
    tr[u].s1=tr[u<<1].s1^tr[u<<1|1].s1;
}
void pushdown(int u){
    if(tr[u].add){
        tr[u<<1].add^=1;
        tr[u<<1|1].add^=1;
        swap(tr[u<<1].s0,tr[u<<1].s1);
        swap(tr[u<<1|1].s0,tr[u<<1|1].s1);
    }
    tr[u].add=0;
}
void build(int u,int l,int r){
    tr[u]={l,r,0,0,0,0};
    if(l==r){
        tr[u].w=b[l];
        if(b[l]==1) tr[u].s1=a[l];
        else tr[u].s0=a[l];
    }
    else{
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        tr[u].add^=1;
        swap(tr[u].s1,tr[u].s0);
    }
    else{
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid) modify(u<<1,l,r);
        if(r>mid) modify(u<<1|1,l,r);
        pushup(u);
    }
}
// node query(int u,int l,int r){
//     if(tr[u].l>=l&&tr[u].r<=r){
//         return tr[u];
//     }
//     else{
//         pushdown(u);
//         node res={0,0,0,0,0};
//         int mid=tr[u].l+tr[u].r>>1;
//         if(l<=mid){
//             res=query(u<<1,l,r);
//         }
//         if(r>mid) modify(u<<1|1,mid+1,r);
    
//     }
// }
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>s;
    s="?"+s;
    for(int i=1;i<=n;i++) b[i]=s[i]-'0';
    build(1,1,n);
    int q;cin>>q;
    while(q--){
        int op;
        cin>>op;
        if(op==1){
            int l,r;cin>>l>>r;
            modify(1,l,r);
        }
        else{
            int x;cin>>x;
            if(x==1) cout<>t;
    while(t--) solve();
    
}

F.画图样例其实可以知道,按照拓扑序直接处理即可,最后会有多个环,每个环的贡献最大是让一个点贡献不能*2,其他都可以

我写的比较麻烦,先拓扑序把不是环的点先存了,再把每个环tarjan缩点,然后单独处理每个环,每个环算完出发点后又dfs存答案0.0

所以用了dfs+拓扑排序+tarjan

#include 
using namespace std;
const int N = 2e5+10,M=2*N,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
int a[N],b[N];
int n, m;
int G[N];
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N],Size[N];
int id[N], scc_cnt;
vector g[N];
int din[N],dout[N];
void tarjan(int u)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u, in_stk[u] = true;
  
        int j = G[u];
        if (!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        }
        else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
    

    if (dfn[u] == low[u])
    {
        ++ scc_cnt;
        int y;
        do {
            y = stk[top -- ];
            in_stk[y] = false;
            id[y] = scc_cnt;
          
        } while (y != u);
    }
}
void solve()
{
    cin>>n;
    top=timestamp=scc_cnt=0;
    for(int i=0;i<=n;i++){
        G[i]=0;
        g[i].clear();
        low[i]=dfn[i]=id[i]=0;
        in_stk[i]=false;
        din[i]=dout[i]=0;
     
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
       G[i]=a[i];
       din[a[i]]++;
    }
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i);
    }   
    queue q;
      vector res;
    for(int i=1;i<=n;i++) if(din[i]==0) q.push(i);
    while(q.size()){
        auto t=q.front();
        q.pop();res.push_back(t);
        int v=G[t];
        if(--din[v]==0){
            q.push(v);
        }
    }

    for(int i=1;i<=n;i++){
    
        g[id[i]].push_back(i);
    }
    
    vector st(n+10,false);
    function dfs=[&](int u){
        if(st[u]) return ;
        st[u]=true;
        res.push_back(u);
        dfs(G[u]);
    };

    for(int i=1;i<=scc_cnt;i++)
    {
        if(g[i].size()==1) continue;
        else{
            sort(g[i].begin(),g[i].end());
            m=g[i].size();
            int now=0,mx=0,idx=0;
            
            for(auto x:g[i]) now+=2*b[x];
            for(int x:g[i])
            {
                if(mx>t;
    while(t--) solve();
    
}

G.首先把左右两边的1去掉没用,

然后思考中间的值,因为处理完后左右两边一定不是1,所以如果区间乘大于1e9

说明至少有60个2相乘,那么中间的1肯定也只能要

然后如果不大于

那么说明中间区间的数加起来不大于60(去掉中间是1的数)

那么直接枚举左右端点即可

#include 
using namespace std;
const int N = 2e5+10,M=2*N,mod=998244353;
#define int long long

typedef long long LL;
typedef pair PII;
int a[N],b[N];
int n, m;

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int l=1,r=n;
    while(a[l]==1&&l1e9){
            cout<1) b[++idx]=i;
        sum+=a[i];
    }
    int ans=sum,ansl=1,ansr=1;
    for(int i=1;i<=idx;i++){
        res=1;
        l=b[i];
        int s=0;
        for(int j=i;j<=idx;j++){
            res*=a[b[j]];
            r=b[j];
            s+=a[b[j]];
            int val=sum-s-(r-l+1-(j-i+1))+res;
            if(val>ans){
                ans=val;
                ansl=l,ansr=r;
            }
        }
    }
    cout<>t;
    while(t--) solve();
    
}

你可能感兴趣的:(算法)