100道codeforces 2500

首先小小容斥一下,用1~r的减去1~l-1的。
1~r的,可以想到数位dp
设f[len][pre][mod]表示从低位数第len位,当前数字的值%2450为pre,当前用过的数字的lcm为mod的方案数
使用limit表示是否贴着上界
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;//1e9+7
ll read(){ll x;scanf("%lld",&x);return x;}
ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;}
int lowbit(int x){return x&(-x);}
int digit[20],mp[2521];
ll f[20][2521][50];
ll dfs(int len,int pre,int mod,int limit)
{
    if(!len)
        return pre%mod==0;
    if(!limit&&f[len][pre][mp[mod]]!=-1)
        return f[len][pre][mp[mod]];
    ll ret=0;
    int ed=limit?digit[len]:9;
    for(int i=0;i<=ed;i++)
        ret+=dfs(len-1,(pre*10+i)%2520,i==0?mod:mod/__gcd(mod,i)*i,limit&&i==ed);
    if(!limit)
        f[len][pre][mp[mod]]=ret;
    return ret;
}
ll ask(ll x)
{
    int len=0;
    while(x)
    {digit[++len]=x%10;x=x/10;
    }
    return dfs(len,0,1,1);
}
void work()
{
    memset(f,-1,sizeof(f));
    ll l=read(),r=read();
    cout<<ask(r)-ask(l-1)<<'\n';
}
int main()
{
    int cnt=0;
    for(int i=1;i<=2520;i++)
        if(2520%i==0)
            mp[i]=++cnt;
    for(int t=read();t;t--)
        work();
}
55D

 

例如,我们把abc看成是
从ab点移动到了bc点
则恢复密码只需要跑欧拉路即可。抄了刘瑾豪的模板然后发现他模板错了,非常难崩
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010,mod=998244353;//1e9+7;
ll read(){ll x;scanf("%lld",&x);return x;}
ll quick(ll a,ll b){ll t=1;while(b){if(b&1)t=t*a%mod;b=b/2;a=a*a%mod;}return t;}
int lowbit(int x){return x&(-x);}
int n,ans[N*2],chu[N],ru[N],tot,cur[N];
vector<int>e[N];
void dfs(int x)
{
    while(cur[x]<e[x].size())
    {
        int t=cur[x];
        cur[x]++;
        dfs(e[x][t]);
    }
    ans[++tot]=x;
}
int main()
{
    int n1=n=read();
    for(int i=1;i<=n;i++)
    {
        string s;
        cin>>s;

        int x=s[0]*130+s[1],y=s[1]*130+s[2];
        e[x].push_back(y);
        ru[y]++;
        chu[x]++;
    }
    n=130*130;
    int root=-1,cnt=0;
    for(int i=n;i>=0;i--)
    {
        if(abs(ru[i]-chu[i])>1)
        {
            cout<<"NO";
            return 0;
        }
        if(ru[i]!=chu[i])
            cnt++;
    }
    if(cnt!=0&&cnt!=2)
        cout<<"NO";
    else
    {
        if(cnt==2)
            for(int i=0;i<=n;i++)
                if(ru[i]<chu[i])
                    root=i;
        if(root==-1)
        {
            for(int i=0;i<=n;i++)
                if(ru[i])
                    root=i;
        }
        
        dfs(root);
        if(n1+1!=tot)
            cout<<"NO";
        else
        {
            cout<<"YES\n";
            cout<<char(ans[tot]/130);
            for(int i=tot;i;i--)
                cout<<char(ans[i]%130);
        }
    }
}
508D

 

考虑根号分治
如果询问长度小于s就暴力,复杂度为O(qs)
如果询问长度大于s,就暴力枚举出现次数大于s/k的那些数字,询问他们在询问中出现了几次,复杂度为qn/s*5logn

跑的飞快
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300010;
int lowbit(int x){return x&(-x);}
ll read(){ll x;scanf("%lld",&x);return x;}
int n,q,s,a[N],cnt[N];
struct node
{
    int siz,v;
    friend bool operator <(node a,node b)
    {
        return a.siz>b.siz;
    }
};
vector<node>o;
vector<int>pos[N];
int ask(int l,int r,int v)
{
    auto b=upper_bound(pos[v].begin(),pos[v].end(),r);
    auto a=lower_bound(pos[v].begin(),pos[v].end(),l);
    return b-a;
}
int main()
{
    n=read();q=read();
    s=sqrt(2.5*n);
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        pos[a[i]].push_back(i);
    }
    for(int i=1;i<=n;i++)
        if(pos[i].size()>=s/5)
            o.push_back({pos[i].size(),i});
    sort(o.begin(),o.end());
    for(int i=1;i<=q;i++)
    {
        int l=read(),r=read(),k=read();
        int len=(r-l+1)/k;
        if(r-l+1<=s)
        {
            int ans=1e6;
            for(int j=l;j<=r;j++)            
                cnt[a[j]]++;
            for(int j=l;j<=r;j++){
                if(cnt[a[j]]>len)
                    ans=min(ans,a[j]);
                cnt[a[j]]--;
            }
            if(ans==1e6)
                ans=-1;
            cout<<ans<<'\n';
        }
        else
        {
            int ans=1e6;
            for(auto [siz,v]:o)
            {
                if(siz<=len)
                    break;
                int num=ask(l,r,v);
                if(num>len)
                    ans=min(ans,v);
            }
            if(ans==1e6)
                ans=-1;
            cout<<ans<<'\n';
        }
    }
}
840D

 

首先,交换aiaj,如果ai不等于aj,必使得逆序对数量奇偶变化
但是这题并没有用
考虑把逆序对放在左端点的vector上
然后从小到大地枚举以i位左端点的逆序对,大胆交换,可以使得相关右端点往前整体挪一位,ai放在了相关右端点的最右边
一直做下去,最后一定会单调的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int lowbit(int x){return x&(-x);}
ll read(){ll x;scanf("%lld",&x);return x;}
int n,a[N],cnt;
struct node
{
    int v,i;
    friend bool operator <(node a,node b)
    {
        return a.v==b.v?a.i<b.i:a.v<b.v;
    }
};
vector<node>b,o[N];
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        b.push_back({a[i],i});
    }
    sort(b.begin(),b.end());
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            if(a[i]>a[j])
{
                o[i].push_back({0,j});
                cnt++;
            }
    cout<<cnt<<'\n';
    for(auto [v,i]:b)
    {
        if(o[i].empty())
            continue;
        reverse(o[i].begin(),o[i].end());
        for(auto [val,j]:o[i])
        {
            cout<<i<<' '<<j<<'\n';
            swap(a[i],a[j]);
        }
    }
}

// 把逆序对找出来,排序
// 然后依次枚举每个逆序对,交换
// 问最后能不能变成有序的
// 比如
// 
// 3 1 2
// 1 2
// 2 3 
// 1 3 
// 
// 
// 
// 先1 2
// 1 3 2 
// 2 3 1
// 2 1 3
// 
// 
// 原来奇数个,交换aiaj
cf1375e

 

posted @ 2025-02-16 15:42  zzuqy  阅读(25)  评论(0)    收藏  举报