牛客多校一
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; }