关于有很多好题写了但是不知道放哪所以就放在同一个博客里了md这标题怎么这么长这件事

不分难度.我只是想把一些好玩或者有思维含量的题塞进来.


无向图的最小环问题

\(n\leq100\),考虑\(Floyd\).

首先很好想,就是枚举一条\(i,j\)间的最短路,然后枚举一个中转点\(k\),求最小.

大概是这样:
image

浅绿色的是\(i,j\)间的最短路,浅蓝色的是\(i,k\)\(k,j\)间的两条单独的边.这是显然正确的.

但是我们要注意一个问题:如果是先跑一边\(Floyd\),再找一遍最短路,是错的.理由显然:这样无法保证枚举的\(k\)不在这条\(i,j\)间的最短路上.所以要利用一下\(Floyd\)的特性(即在枚举到\(k\)之前\(k\)不会作为任意两点最短路径上的中转点)一边跑\(Floyd\),一边更新答案.

Code
#include<bits/stdc++.h>

namespace Lemuen_Daily
{
    #define il inline
    #define endl '\n'
    #define ll long long
    #define ldb long double
    #define Croll(i,l,r) for(int i=l;i<=r;++i)
    #define Troll(i,l,r) for(int i=l;i>=r;--i)

    #define itn int
    #define mian main
    
    using std::cout;

    const int maxn=1017;
    const int inf=0x7f7f7f7f;

    il ll read()
    {
        ll f=1,x=0;char w=getchar();
        while(w<'0'||w>'9')
        {if(w=='-')f=-1;w=getchar();}
        while(w>='0'&&w<='9')
        {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
        return f*x;
    }
}using namespace Lemuen_Daily;

ll n,m;
ll ans;

ll mp[maxn][maxn];
ll dis[maxn][maxn];

ll min(ll a,ll b){return a>b?b:a;}

itn mian()
{
    n=read();m=read();
    
    Croll(i,1,n)
        Croll(j,1,n)
        {
            if(i==j)continue;
            mp[i][j]=dis[i][j]=inf;
        }ans=inf;

    Croll(i,1,m)
    {
        ll u=read(),v=read();
        ll w=read();
        dis[u][v]=dis[v][u]=min(dis[u][v],w);
        mp[u][v]=mp[v][u]=min(mp[u][v],w);
    }

    // Croll(i,1,n)
    //     Croll(j,1,n)
    //         cout<<i<<" "<<j<<" "<<dis[i][j]<<endl;

    Croll(k,1,n)
    {
        Croll(i,1,k-1)
            Croll(j,i+1,k-1)
                ans=min(ans,dis[i][j]+mp[i][k]+mp[k][j]);

        Croll(i,1,n)
            Croll(j,1,n)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }

    if(ans==inf)
        cout<<"No solution."<<endl;
    else
        cout<<ans<<endl;
    
    return 0;
}

HASH

乐子题.Trump昨天晚上roll出来的.要稍微动下脑子.

首先一眼爆搜.但是 \(26^{10}\) 显然过不去.考虑折半搜索.
左半边好说,从0开始搞就行了.
问题是右边咋弄:我们使其初始值为k,执行 该 \(Hash\) 运算法则 的逆运算.

然后想怎么搞这个逆运算.
我们设当前Hash值为 \(Ha\) ,当前运算后结果为 \(y\) .

则有

\[(33Ha \oplus ord ) \mod 2^m = y \]

尝试交换运算顺序.易化简为

\[33Ha \mod 2^m = y \oplus ord \]

那显然,\(Ha\) 等于 \((y \oplus ord)\) 乘上 \(33 \mod 2^m\) 的逆元.

Code
#include<bits/stdc++.h>

namespace Lemuen_Daily
{
    #define il inline
    #define endl '\n'
    #define ll long long
    #define ldb long double
    #define Croll(i,l,r) for(int i=l;i<=r;++i)
    #define Troll(i,l,r) for(int i=l;i>=r;--i)

    #define itn int
    #define mian main
    
    using std::cout;

    const int maxn=1<<25;
    const ll inf=0x7f7f7f7f7f;

    il ll read()
    {
        ll f=1,x=0;char w=getchar();
        while(w<'0'||w>'9')
        {if(w=='-')f=-1;w=getchar();}
        while(w>='0'&&w<='9')
        {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
        return f*x;
    }
}using namespace Lemuen_Daily;

int n,k,m;

int cnt[maxn];
ll ans,inv;

void dfs1(int c,int now)
{
    if(c==n/2)
        return cnt[now]++,void();
    
    Croll(i,1,26)
        dfs1(c+1,((now*33)^i)%m);
}

void dfs2(int c,int now)
{
    if(c==0)
        return ans+=cnt[now],void();
    
    Croll(i,1,26)
        dfs2(c-1,(now^i)*inv%m);
}

int mian()
{
    n=read();k=read();m=1<<(read());

    Croll(i,1,m-1)
        if(i*33%m==1)inv=i;

    dfs1(0,0);dfs2((n+1)/2,k);
    cout<<ans<<endl;

    return 0;
}

Inversion Counting

我是不会告诉你其实我是因为这题标签有平衡树才做的.

这题标签有平衡树.但是并不需要平衡树.这题操作时在反转区间嘛,然后求逆序对.

容易发现,实际上有变化的逆序对只有完全在这个区间内的.换句话说,反转操作对该区间外的答案无影响.

那么这个区间内的逆序对个数是怎么变得捏?显然,原来的逆序对都会变为正序的;原来的正序对都会变为逆序的.但是顺着这条路想的话好像最终还是会跑到求区间逆序对上.那这题就没意思了.

所以换种思路.答案只要求输出奇偶,所以从奇偶性方面考虑.那容易发现区间原正序对个数奇偶性等于现在逆序对个数的奇偶性.设区间长度为 \(len\) ,则区间内数对总数为 \(\frac{len*(len-1)}{2}\) .再设反转后区间逆序对个数为 \(num\) ,则现区间内正序对数量为 \(num\) .则现区间内逆序对数量为 \(\frac{len*(len-1)}{2}-num\) .

然后捏,大的来了:

反转前逆序对数量 减去 反转前后逆序对数量差 就是 反转后逆序对数量.

所以捏,想判断 反转后逆序对数量的奇偶性,只需判断 反转前后逆序对数量差 的奇偶性.

那这个数量差很显然是 \(\frac{len*(len-1)}{2}-2num\) . \(2num\) 是偶数(显然),那么我们现在只需要判断 \(\frac{len*(len-1)}{2}\) 的奇偶性了.这个是平凡的.

Code
#include<bits/stdc++.h>

namespace Lemuen_Daily
{
    #define endl '\n'
	#define il inline
    #define ll long long
    #define ldb long double
    #define Croll(i,l,r) for(int i=l;i<=r;++i)
    #define Troll(i,l,r) for(int i=l;i>=r;--i)
    #define cerr_time std::cerr<<(double)clock()/CLOCKS_PER_SEC
    
    const int maxn=101700;
    const ll inf=0x7f7f7f7f7f;
    
    il int read()
    {
        int f=1,x=0;char w=getchar();
        while(w<'0'||w>'9')
        {if(w=='-')f=-1;w=getchar();}
        while(w>='0'&&w<='9')
        {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
        return f*x;
    }
}using namespace Lemuen_Daily;

int n,m;
int w[maxn];

bool flag;
int num;

namespace Lemuen_BIT
{
    int tr[maxn];

    int lowbit(int x)
    {return x&(-x);}
    void add(int x)
    {
        while(x<=n)
        {
            tr[x]++;
            x+=lowbit(x);
        }
    }
    int query(int x)
    {
        int ans=0;
        while(x)
        {
            ans+=tr[x];
            x-=lowbit(x);
        }
        return ans;
    }

    void Get()
    {
        Troll(i,n,1)
        {
            num+=query(w[i]);
            add(w[i]);
        }
    }
}

int main()
{
    n=read();
    Croll(i,1,n)
        w[i]=read();

    Lemuen_BIT::Get();

    flag=!(num%2);

    m=read();
    while(m--)
    {
        int l=read(),r=read();

        int p=r-l+1;
        if((p*(p-1)/2)%2)
            flag=!flag;
        
        if(flag)
            std::cout<<"even"<<endl;
        else
            std::cout<<"odd"<<endl;
    }

    return 0;
}

集合 First

《关于我最后一个小时才想起来有场比赛没打,最后二十分钟想这道题但是没想出来,然后比赛结束不到十分钟想出来了这回事》

乐子题.


数据范围到 \(1e16\),\(O(n)\) 都不用想.试着想想能否单独计算每个数的贡献.

首先我们容易得出一个结论:因为从大到小排序,所以一个数的排名只与"大于他的数的个数"有关.


因为最后一个数没有大于他的数,所以先考虑前 \(n-1\) 个数.那么对于每个 \(x\),大于它的数会有 \(n-x\) 个.(后文用 \(m\) 替代 \(n-x\)).这 \(m\) 个数,能组成的集合个数为 \(2^{m}\) 个.因为要求x的排名,所以考虑这 \(m\) 个数组成的集合的大小.易得,有 \(2^{m-1}\) 个集合大小为奇数,剩下 \(2^{m-1}\) 个的大小为偶数.
所以我们就能得到一个很抽象但是正确的结论:

\(n-1\) 个数,贡献均为 \(0\).

逆天吧?我也觉得逆天.


然后再来单独考虑最后一个数.我们容易发现,无论怎么组合,他都始终排在第一位,也就是说,他只会产生正贡献.
那么它会产生多少次贡献呢?因为前 \(n-1\) 个数能组成 \(2^{n-1}\) 个集合,所以为 \(2^{n-1}\) 次.

所以,我们得出总结论:

答案为 \(n \times 2^{n-1}\).

Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define endl '\n'
#define int long long
const int mod=911451407;
#define Croll(i,l,r) for(int i=l;i<=r;++i)
#define Troll(i,l,r) for(int i=l;i>=r;--i)
//////////
int n;

int qp(int,int);
//////////
il int read();
//////////
signed main()
{
    n=read();

    int ans=n%mod*qp(2,n-1)%mod;

    cout<<ans<<endl;

    return 0;
}
//////////
int qp(int x,int k)
{
    int res=1;
    while(k)
    {
        if(k & 1)res=res*x%mod;
        x=x*x%mod;k>>=1;
    }
    return res;
}
//////////
il int read()
{
    int f=1,x=0;char w=getchar();
    while(w<'0'||w>'9')
    {if(w=='-')f=-1;w=getchar();}
    while(w>='0'&&w<='9')
    {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
    return f*x;
}
posted @ 2023-10-31 19:23  Spade-A  阅读(120)  评论(5)    收藏  举报