牛客多校一


A

假设数组a和b前m个数的rmq相等,即所有区间最小值相同
新加入一个数,多了m+1个区间,只需要考虑新增的区间
找到第m+1左边第一个比它小的数,设它的位置是p
小于等于p的位置rmq的值和第m+1个数就没关系了
大于p的位置rmq结果显然是第m+1个数
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (500000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n;
int a[maxn],b[maxn];
int s1[maxn],s2[maxn],p1,p2;
int main()
{
    while(RD1(n)!=EOF)
    {
        p1=p2=0;
        for(int i=1;i<=n;i++)RD1(a[i]);
        for(int i=1;i<=n;i++)RD1(b[i]);
        int ans=0;
        for(int i=1;i<=n;i++){    
            while(p1&&a[s1[p1]]>a[i])p1--;
            while(p2&&b[s2[p2]]>b[i])p2--;
            if(p1!=p2)break;
            else 
            {
            ans=i;
            s1[++p1]=i,s2[++p2]=i;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
} 


C

总体思路先从大到小排序,再贪心,具体思路参考https://blog.csdn.net/dxyinme/article/details/96455593
关键细节
ai取值是离散的,而pi是连续的,因此先将整个式子扩大m倍。
当m不能再将所有前面的数削减到当前数a[st]时,确定了前st-1个数由m弥补。
m可能会剩余rem,这时候要均摊,即前面每个数等于a[st-1]-rem/st(以整数形式通分)
最终式子

通分后
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (10000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
int a[maxn];
int main()
{
    while(RD2(n,m)!=EOF)
    {
        for(int i=0;i<n;i++)RD1(a[i]);
        sort(a,a+n,greater<int>());
        int st;
        int d=0;
        for(st=1;st<n;st++)
        {
            int t=(a[st-1]-a[st])*st;
            if(d+t>m)break;
            else d+=t;
        }
        int rem=m-d;
        //see(rem),see(st),NL;
        ll num1=1LL*(a[st-1]*st-rem)*(a[st-1]*st-rem);
        for(int i=st;i<n;i++)num1+=1LL*a[i]*a[i]*st;
        ll num2=1LL*st*m*m;
        ll g=__gcd(num1,num2);
        num1/=g,num2/=g;
        if(num2==1)printf("%lld\n",num1);
        else printf("%lld/%lld\n",num1,num2);
    }
    return 0;
} 


E

关键思路:前a+b个字母,a个A,b个B,a-b<=n,否则a-b>n,a>n,剩下能用的a‘<m,凑BA的时候就不够了
同理,b-a<=m
然后用到卡特兰数的'折线形式'
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (5000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
ll fac[maxn]={1};
ll qpow(ll a,ll k)
{
    ll res=1;
    while(k){
        if(k&1)res=res*a%mod;
        k>>=1,a=a*a%mod;
    }return res;
}
ll c(int n,int m)
{
    if(n==m||m==0)return 1;
    if(m>n)return 0;
    return fac[n]*qpow(fac[m],mod-2)%mod*qpow(fac[n-m],mod-2)%mod;
}
int main()
{
    for(ll i=1;i<=4000;i++)fac[i]=fac[i-1]*i%mod;
    while(RD2(n,m)!=EOF)
    {
        cout<<((c(n*2+m*2,m+n)-c(n*2+m*2,m-1)-c(n*2+m*2,n-1))%mod+mod)%mod<<endl;
    }
    return 0;
}


H

给定一个n个数的集合,求所有异或和为0的子集的大小之和
技巧多,思维量巨大
总体思路是,考虑单点贡献,只要check当前这个元素是否能由剩下的n-1个元素表示,并且这剩下的n-1个元素能构成为0的集合个数
程序优化的时候用到了类似矩阵秩的性质,即线性基集合的大小始终不变
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (100000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n;
ll a[maxn];
ll v[70];
ll v1[70];
ll v2[70];
vector<int>r;
void show(ll*v)
{
    for(int i=0;i<64;i++)see(i),see(v[i]),NL;
}
bool insert(ll x,ll*vv)
{
    for(int i=60;i>=0;i--)
    {
        if(!(x&(1LL<<i)))continue;
        if(!vv[i]){vv[i]=x;return 1;}
        else x^=vv[i];
    }return 0;
}
ll qpow(ll a,ll k)
{
    ll res=1;while(k)
    {
        if(k&1)res=a*res%mod;
        a=a*a%mod,k>>=1;
    }return res;
}
bool cmp(ll a,ll b)
{
    return a>b;
}
int main()
{
    while(RD1(n)!=EOF)
    {CLR(v),CLR(v1);r.clear();
        int cnt=0;
        int c2=0;
        for(int i=1;i<=n;i++)RDL1(a[i]);
        for(int i=1;i<=n;i++)
        {
            int t=insert(a[i],v);
            if(!t)c2+=insert(a[i],v1);
            else r.push_back(i);
            cnt+=t;
        }
        ll ans=n-cnt;
        ll delt=0;
        if(n>cnt)delt=qpow(2,n-cnt-1)%mod;
        if(delt==0){printf("0\n");continue;}
        for(int i=0;i<r.size();i++)
        {
            memcpy(v2,v1,sizeof(v1));
            int c3=c2;
            for(int j=0;j<r.size();j++)
            {
                if(j==i)continue;
                c3+=insert(a[r[j]],v2);
            }
            if(!insert(a[r[i]],v2)) ans++;
        }
        printf("%lld\n",ans*delt%mod);
    }
    return 0;
}


牛客多校四

A

这里用两次dfs比较简单
先把有人的点存x[]数组,去重排序
从x里挑一个点p1,dfs,找到在x里和它最远的点p2,
再从p2dfs,找到x里找和它最远的点,此时的距离就是x[]里的点构成子树的直径
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (100000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,k;
int head[maxn],to[maxn<<1],pre[maxn<<1],tot;
bool tg[maxn];
int x[maxn];
int dis1[maxn],dis2[maxn];
void adde(int u,int v)
{
    to[++tot]=v,pre[tot]=head[u],head[u]=tot;
}
void dfs1(int u,int f)
{
    for(int i=head[u];i;i=pre[i])
    {
        int v=to[i];if(v==f)continue;
        dis1[v]=dis1[u]+1;dfs1(v,u);
    }
}
void dfs2(int u,int f)
{
    for(int i=head[u];i;i=pre[i])
    {
        int v=to[i];if(v==f)continue;
        dis2[v]=dis2[u]+1;dfs2(v,u);
    }
}
int main()
{
    RD2(n,k);for(int i=1;i<n;i++)
    {
        int u,v;RD2(u,v);adde(u,v),adde(v,u);
    }
    for(int i=0;i<k;i++)
    {
        RD1(x[i]);
    }
    sort(x,x+k);k=unique(x,x+k)-x;
    if(n==1){printf("0");return 0;}
    dfs1(x[0],0);
    //for(int i=0;i<k;i++)see(x[i]),see(dis1[x[i]]),NL;
    int ed=0;
    for(int i=1;i<k;i++)
    {
        if(dis1[x[i]]>dis1[x[ed]])ed=i;
    }
    dfs2(x[ed],0);
    int ans=0;
    for(int i=0;i<k;i++)
    {
        ans=max(ans,dis2[x[i]]);
    }
    printf("%d",(ans+1)/2);
    return 0;
} 


D

疯狂分类讨论,详细思路见题解
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxn (3000000+10)
#define maxm (1000000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (1000000007)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll n;
ll a1[100],a2[100];
int main()
{
	int ttt;RD1(ttt);while(ttt--)
	{
		RDL1(n);int p1=0,p2=0;
		if(n%3==0){cout<<"1 "<<n<<endl;continue;}
		cout<<"2 ";
		for(int i=0;i<=60;i++)
		{
			if(n&(1LL<<i))
			{
				ll r=(1LL<<i)%3;
				if(r==1)a1[p1++]=(1LL<<i);
				else a2[p2++]=(1LL<<i);
			}
		}
		if(n%3==1)
		{
			if(p1&&p2)
			{
				ll x1=a1[0]|a2[0];
				ll x2=n&(~a1[0]);
				cout<<x1<<' '<<x2<<endl;
			}
			else if(p1)
			{
				ll x1=a1[0]|a1[1]|a1[2];
				ll x2=n&(~a1[0]);
				cout<<x1<<' '<<x2<<endl;
			}
			else
			{
				ll x1=a2[0]|a2[1]|a2[2];
				ll xx=a2[0]|a2[1];
				ll x2=n&(~xx);
				cout<<x1<<' '<<x2<<endl;
			}
		}
		else
		{
			if(p1&&p2)
			{
				ll x1=a1[0]|a2[0];
				ll x2=n&(~a2[0]);
				cout<<x1<<' '<<x2<<endl;
			}
			else if(p1)
			{
				ll x1=a1[0]|a1[1]|a1[2];
				ll xx=a1[0]|a1[1];
				ll x2=n&(~xx);
				cout<<x1<<' '<<x2<<endl;
			}
			else
			{
				ll x1=a2[0]|a2[1]|a2[2];
				ll x2=n&(~a2[0]);
				cout<<x1<<' '<<x2<<endl;
			}
		}
	}
	return 0;
}


牛客多校五

G

s比t长的时候用组合数计算,数字开头为0的情况减掉
s和t一样长的时候用类似lcs的做法。
设dp[i][j]是s的前i位中与t的前j位中相同的子序列个数(不一定以s[i]结尾)



坑:预处理dp[i][0]=1
#include<bits/stdc++.h>
#define RD1(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d %d",&x,&y)
#define RD3(x,y,z) scanf("%d %d %d",&x,&y,&z)
#define RDL1(x) scanf("%lld",&x)
#define RDL2(x,y) scanf("%lld %lld",&x,&y)
#define RDL3(x,y,z) scanf("%lld %lld %lld",&x,&y,&z)
#define CLR(x) memset(x,0,sizeof(x))
#define NEG(x) memset(x,0xff,sizeof(x))
#define maxm (1000000+10)
#define maxn (3000+10)
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mod (998244353)
#define pi acos(-1)
#define eps 1e-14
#define acc ios::sync_with_stdio(false)
#define inf 0x3f3f3f3f
#define INF(x) memset(x,inf,sizeof(x))
#define CLRQ(Q) while(!(Q).empty())(Q).pop()
#define see(x) (cerr<<(#x)<<'='<<(x)<<' ')
#define NL printf("\n")
#define fi freopen("C:\\Users\\Administrator\\Desktop\\in","r",stdin)
#define fo freopen("C:\\Users\\Administrator\\Desktop\\out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
char s[maxn],t[maxn];
ll dp[maxn][maxn];
ll fac[maxn];
void init()
{
	fac[0]=1;
	for(int i=1;i<=3000;i++)fac[i]=fac[i-1]*i%mod;
	for(int i=0;i<=3000;i++)dp[i][0]=1;
}
ll qpow(ll a,ll k)
{
	ll res=1;while(k)
	{
		if(k&1)res=res*a%mod;
		a=a*a%mod;
		k>>=1;
	}return res;
}
ll c(int n,int m)
{
	if(m>n)return 0;
	return fac[n]*qpow(fac[m],mod-2)%mod*qpow(fac[n-m],mod-2)%mod;
}
void show()
{//see(n),see(m),NL;
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=n;i++)see(i),see(j),see(dp[i][j]),NL;
	}
}
int main()
{
	int ttt;
	init();
	RD1(ttt);while(ttt--)
	{
		ll ans=0;
		RD2(n,m);scanf("%s%s",s+1,t+1);
		
		for(int j=1;j<=m;j++)
		for(int i=j;i<=n;i++)
		{
			dp[i][j]=dp[i-1][j];
			if(s[i]==t[j])dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
			else if(s[i]>t[j])
				ans=(ans+dp[i-1][j-1]*c(n-i,m-j)%mod)%mod;
		}
		for(int i=m+1;i<=n;i++)
		{
			ans=(ans+c(n,i))%mod;
			for(int j=1;j+i-1<=n;j++)if(s[j]=='0')
				ans=(ans+mod-c(n-j,i-1))%mod; 
		}
		//show();
		cout<<ans<<endl;
	} 
	return 0;
}