A
简单的组合数学。考虑枚举为1的个数的长度为x,则其他数除了最后一位的0外都可以乱填。
对于末尾为1的数,显然每一位都是独立的,单独考虑每一位。
显然只要该位上有一个0即可,经典容斥:减去全为1的这一种情况。
#include<bits/stdc++.h> using namespace std; #define int long long const int N=5005; int f[N][N]; int qpow(int a,int b,int mod){ int ret=1; while(b){ //TODO if(b&1) ret=ret*a%mod; a=a*a%mod; b>>=1; } return ret; } signed main(){ int n,m,p;cin>>n>>m>>p; f[0][0]=1; for(int i=1;i<=n;i++){ f[i][0]=1; for(int j=1;j<=i;j++){ f[i][j]=(f[i-1][j-1]+f[i-1][j])%p; } } int ans=0; for(int x=1;x<=n;x++){ int tmp=0; int a1=(qpow(2,x,p)-1+p)%p; a1=qpow(a1,m-1,p); int a2=qpow(2,m-1,p); a2=qpow(a2,n-x,p); int a3=f[n][x]; tmp=a1*a2%p*a3%p; ans=(ans+tmp)%p; } cout<<ans<<"\n"; }
B
A的plus版,但也不难。多了一个限制是:能选出2个不同的子序列使得其AND和为1。
2个不同的情况很多种不好计算,反向考虑什么时候选不出来?当且仅当每个末尾为1的数都要选。
问题化简成有n个数要覆盖m个位,每个数都至少有一个自己唯一覆盖的位置。
dp[i][j]=(dp[i-1][j-1]+dp[i][j-1])*i
#include<bits/stdc++.h> using namespace std; const int N=5005; typedef long long ll; #define int long long int f[N][N],n,m,p; int qpow(ll a,int b){ a%=p; ll ret=1; while(b){ //TODO if(b&1) ret=ret*a%p; a=a*a%p; b>>=1; } return ret; } int dp[N][N]; signed main(){ cin>>n>>m>>p; f[0][0]=1; for(int i=1;i<=5002;i++){ f[i][0]=1; for(int j=1;j<=i;j++){ f[i][j]=(f[i-1][j-1]+f[i-1][j])%p; } } ll ans=0; for(int x=1;x<=n;x++){ ll a1=(qpow(2,x)-1+p)%p;a1=qpow(a1,m-1); int a2=qpow(2,m-1);a2=qpow(a2,n-x); int a3=f[n][x]; ans=(ans+a1*a2%p*a3%p)%p; } // cout<<"ans: "<<ans<<"\n"; dp[0][0]=1; for(int i=1;i<=n;i++){ for(int j=i;j<=m;j++){ dp[i][j]=1ll*((dp[i-1][j-1]+dp[i][j-1])%p)*i%p; // cout<<i<<" "<<j<<" :"<<dp[i][j]<<"\n"; } } ll tot=0; for(int k=2;k<=n;k++){ int x=qpow(2,(m-1)*(n-k)); int y=(qpow(2,k)-k-1+p)%p; ll tmp=1; for(int t=m-1;t>=k;t--){ tot+=tmp*f[m-1][t]%p*dp[k][t]%p*f[n][k]%p*x%p; // cout<<k<<" "<<t<<" : "<<f[m-1][t]*dp[k][t]%p*f[n][k]%p*qpow(2,(m-1)*(n-k)%p)%p*qpow((qpow(2,k)-k-1+p)%p,m-1-t)<<"\n"; tot%=p; tmp=tmp*y%p; } } tot+=(ll)qpow(2,(m-1)*(n-1))*n%p; tot%=p; ans=(ans-tot+p)%p; cout<<ans<<"\n"; }
C
签到
#include<bits/stdc++.h> using namespace std; #define int long long const int mod=1e9+7; signed main(){ ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int q; cin>>q; int sum=0;// a1+a2+a3 int tot=0;// s1+s2+s3 int len=0; vector<int>a; while(q--){ int t,v; cin>>t>>v; for(int i=1;i<=t;i++){ sum=(sum-a.back()+mod)%mod; tot=(tot-a.back()*len%mod+mod)%mod; len--; a.pop_back(); } a.push_back(v); // cout<<tot<<" "<<len<<" "<<sum<<"\n"; tot+=(len*v%mod+v)%mod; tot%=mod; len++; sum+=v; sum%=mod; cout<<tot<<"\n"; } }
D
没场切,当队友说出这个模数很小,先算出答案后再取模而我没有反对意见时,这道题就已经完蛋了。。
切入点在于模数,没有很大,且是2^21,启发我们在位运算上做文章。
显然先拆位,设当前在第 k 位,拆完后询问转化为有多少后缀和在第 k 位上为1。
后缀和不好处理,如果直接从后缀和入手,每次操作对整个数列都会产生影响。
考虑转化成前缀和,则后缀和 s[i]=sum[n]-sum[i-1],求有多少个 s[i] 在第k位上为1。
这里直接算肯定也不行,”在第k位上为1“可以转化成模意义下的加法运算:(sum[n]-sum[i-1]) % (2^(k+1)) >= 2^k
令x=-sum[i-1] % (2^(k+1)) => (sum[n]+x) % (2^(k+1)) >= 2^k
又 (sum[n]+x) % (2^(k+1)) <= 2^(k+1) 所以 2^(k+1) >= (sum[n]+x) % (2^(k+1)) >= 2^k 每次询问相当于固定sum[n],求有多少x满足条件。满足条件的x是一段(或者两段连续的值) R = 2^(k+1)-sum[n] >= x >= 2^k -sum[n] = L 若 L <= R,直接询问[L,R]有多少个数即可,用权值树状数组维护 若 R<L ,说明在mod意义下R溢出了,跑到了前面去,就是两段:[0,R] 和 [L,2^(k+1)-1]#include<bits/stdc++.h> using namespace std; const int N = 2097152+5; int lowbit(int x) { return x&(-x); } struct ft{ int a[N],n; void init(int len){ n=len; for(int i=1;i<=n;i++) a[i]=0; } void add(int pos,int v){ pos++; for(int i=pos;i<=n;i+=lowbit(i)) a[i]+=v; } int sum(int pos){ if(pos<0) return 0; pos++; int ret=0; // cout<<pos<<" LEN: "<<n<<endl; for(int i=pos;i;i-=lowbit(i)) ret+=a[i]; return ret; } int query(int l,int r){ if(l>r) return 0; return sum(r)-sum(l-1); } }BIT[21]; int main(){ ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); for(int i=0;i<=20;i++) BIT[i].init((1<<(i+1))); vector<int>a; int q;cin>>q; int sum=0; for(int k=0;k<=20;k++){ int tot,p=1<<(k+1); tot=(p-sum%p)%p; BIT[k].add(tot,-1); } while(q--){ //TODO int t,v;cin>>t>>v; for(int j=1;j<=t;j++){ int x=a.back(); for(int k=0;k<=20;k++){ int tot,p=1<<(k+1); tot=(p-sum%p)%p; BIT[k].add(tot,-1); } sum-=x; a.pop_back(); } sum+=v; a.push_back(v); for(int k=0;k<=20;k++){ int tot,p=1<<(k+1); tot=(p-sum%p)%p; // cout<<k<<" add "<<tot<<"\n"; BIT[k].add(tot,1); } int ans=0; for(int k=0;k<=20;k++){ int p=1<<(k+1),p1=1<<k; int l=(p1-sum%p+p)%p,r=(p-1-sum%p+p)%p,cnt=0; // cout<<"["<<l<<","<<r<<"]"<<"\n"; // cout<<BIT[k].query(l,r)<<" "<<BIT[k].query(0,r)<<" "<<BIT[k].query(l,p-1)<<"\n"; if(l<=r) cnt=BIT[k].query(l,r); else cnt=cnt+BIT[k].query(0,r)+BIT[k].query(l,p-1); if(cnt&1) { // cout<<l<<" "<<r<<"\n"; ans|=(1<<k); } } cout<<ans<<"\n"; } }标签:return,int,sum,多校,ret,cin,2024,牛客,long From: https://www.cnblogs.com/liyishui2003/p/18309078