牛客练习赛52-记录
正題
比賽鏈接:https://ac.nowcoder.com/acm/contest/1084#question
成績
T1:T1:T1:數數
題目大意
給出nnn,求∑i=1n∑j=1n(i?j)\sum_{i=1}^n \sum_{j=1}^n (i*j)i=1∑n?j=1∑n?(i?j)
和
∏i=1n∏j=1n(i?j)\prod_{i=1}^n\prod_{j=1}^n(i*j)i=1∏n?j=1∏n?(i?j)
解題思路
第一個答案顯然就是
(∑i=1ni)?(∑j=1nj)(\sum_{i=1}^ni)*(\sum_{j=1}^n j)(i=1∑n?i)?(j=1∑n?j)
等差數列求和即可O(1)O(1)O(1)解決。
第二個是
∏i=1ni2n?(∏i=1ni)2n\prod_{i=1}^ni^{2n} \Rightarrow\ (\prod_{i=1}^n i)^{2n}i=1∏n?i2n??(i=1∏n?i)2n
預處理后O(log?n)O(\log n)O(logn)回答。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll XJQ=998244353; ll t,n,s[10010000],sum; ll power(ll x,ll b) {ll ans=1;while(b){if(b&1) ans=ans*x%XJQ;x=x*x%XJQ;b>>=1;}return ans; } int main() {scanf("%lld",&t);s[0]=1;for(ll i=1;i<=1e7;i++)s[i]=s[i-1]*i%XJQ;while(t--){scanf("%lld",&n);sum=((n+1)*n/2)%XJQ;printf("%lld %lld\n",sum*sum%XJQ,power(s[n],2*n));} }T2:GalahadT2:GalahadT2:Galahad
題目大意
一個長度為nnn的序列,求[l,r][l,r][l,r]這個區間的和,需要注意的是若一個數出現多次的話只計算一次。
解題思路
莫隊會T\color{red}\texttt{\huge莫隊會T}莫隊會T
我們先將詢問按照右端點單調不降排序,然后我們用指針進行掃描。
現在我們不需要考慮右端點了,只需要在已有的數中每次詢問一個左端點。
我們考慮如何計算,因為不能重復,我們可以對于每個數計算出一個可以影響的范圍,也就是最右邊的那個數。
我們現在得出一種算法,我們每次右端點移動時加入一個數,若這個數之前沒有就直接在樹狀數組上加入,否則就將前面的那個賦值為0后再進行加入。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define lowbit(x) (x&-x) #define ll long long using namespace std; const ll N=5e5+100; struct node{ll l,r,id; }a[N]; ll n,m,w[N],t[N],ans[N],v[N],sum; void change(ll x,ll z) {while(x<=n){t[x]+=z;x+=lowbit(x);} } ll ask(ll x) {ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans; } bool cMp(node x,node y) {return x.r<y.r;} int main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lld",&w[i]);for(ll i=1;i<=m;i++)scanf("%lld%lld",&a[i].l,&a[i].r),a[i].id=i;sort(a+1,a+1+m,cMp);ll tail=1;for(ll i=1;i<=m;i++){while(tail<=a[i].r){if(v[w[tail]]) change(v[w[tail]],-w[tail]);else sum+=w[tail];v[w[tail]]=tail;change(tail,w[tail]);tail++;}ans[a[i].id]=sum-ask(a[i].l-1);}for(ll i=1;i<=m;i++)printf("%lld\n",ans[i]); }T3:T3:T3:烹飪
題目大意
nnn個數的序列aaa,在其中選出若干個組成無序序列bbb。使得N+∈∑(bi?ki)\mathbb{N}^+\in \sum (b_i*k_i)N+∈∑(bi??ki?)
kik_iki?為任意整數。
求有多少種選擇方案數。
解題思路
根據裴蜀定理,我們有ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b),若gcd(a,b)=1gcd(a,b)=1gcd(a,b)=1那么就可以變成任意正整數。我們可以將其擴展到多元。
gcd(a,b)x+cy=gcd(a,b,c)?ax+by+cz=gcd(a,b,c)gcd(a,b)x+cy=gcd(a,b,c)\Rightarrow ax+by+cz=gcd(a,b,c)gcd(a,b)x+cy=gcd(a,b,c)?ax+by+cz=gcd(a,b,c)
以此類推我們可以得出若我們選擇的無序序列bbb的gcd=1gcd=1gcd=1那么就滿足條件。
我們依次設立dpdpdp,設fi,jf_{i,j}fi,j?表示到第iii個,gcdgcdgcd之和為jjj時的方案數。我們有
fi,gcd(i,j)=∑fi?1,jf_{i,gcd(i,j)}=\sum f_{i-1,j}fi,gcd(i,j)?=∑fi?1,j?
這里我們倒過來轉移即可,下面的代碼是滾動了的。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll XJQ=998244353; ll n,num,f[2100]; ll power(ll x,ll b) {ll ans=1;while(b){if(b&1) ans=ans*x%XJQ;x=x*x%XJQ;b>>=1;}return ans; } int main() {scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld",&num);f[num]=(f[num]+1)%XJQ;for(ll j=1;j<=2000;j++)(f[__gcd(j,num)]+=f[j])%=XJQ;}printf("%lld",(f[1]*power(2,XJQ-2))%XJQ); }T4:T4:T4:粉絲群
題目大意
求有多少個nnn個數的序列滿足以下條件
求有多少個,和字典序第kkk小的方案的異或和。
解題思路
結論題,打表找一下就好了。
我們會發現方案數是n?1n-1n?1個111和一個n+1n+1n+1,還有若是奇數的話還有一個全是222的方案。
證明一下(十分感性),此時我們有一個長度為序列nnn,此時對于每個1≤ai≤n1\leq a_i\leq n1≤ai?≤n。
那么我們發現若一個數為2+k2+k2+k那么至少就會有kkk個數為111,假設最終能組成nnn的有lll個數那么有
2l+∑i=1lki=n?z(z∈[0,∑i=1lk])2l+\sum_{i=1}^l k_i=n-z(z\in [0,\sum_{i=1}^l k])2l+i=1∑l?ki?=n?z(z∈[0,i=1∑l?k])
?∑i=1lki≥n?2l?∑i=1lk\Rightarrow \sum_{i=1}^l k_i\geq n-2l-\sum_{i=1}^l k?i=1∑l?ki?≥n?2l?i=1∑l?k且∑i=1lki≤n?2l\sum_{i=1}^l k_i\leq n-2li=1∑l?ki?≤n?2l
顯然此時對于任意∑i=1lki>0\sum_{i=1}^l k_i>0∑i=1l?ki?>0都有解
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; ll n,k; int main() {scanf("%lld%lld",&n,&k);printf("%lld\n",n+(n&1)-(n==1));if(n&1) printf("%lld",(k==n)?2:(n+1));else printf("%lld",(n+1)^1); }總結
以上是生活随笔為你收集整理的牛客练习赛52-记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中秋送礼送啥最合适 中秋送什么礼物好
- 下一篇: NOI.AC-random【期望概率,统