[CSP-S模拟测试96]题解
以后不能再借没改完题的理由不写题解了……
A.求和
求$\sum \sum i+j-1$
柿子就不化了吧……这年头pj都不考这么弱智的公式化简了……
坑点1:模数不定,可能没有2的逆元,那么只要先把乘数里的2去掉就好了。
坑点2:1e18炸long long $\rightarrow$ 慢速乘即可
#include<cstdio> #include<iostream> #include<cstring> #include<vector> using namespace std; typedef long long ll; ll x,y,xx,yy,mod; ll mul(ll a,ll b) { ll res=0; while(b) { if(b&1)res+=a,res%=mod; a=(a+a)%mod; b>>=1; } return res; } vector<ll> fac; #define F int main() { #ifdef F freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); #endif /*mod=1e9+7; cout<<mul(100000,3)<<endl;*/ scanf("%lld%lld%lld%lld%lld",&x,&y,&xx,&yy,&mod); int cnt=1; fac.push_back(x+xx); fac.push_back(xx-x+1); fac.push_back(yy-y+1); for(int i=0;i<3;i++) if(cnt&&fac[i]%2==0)fac[i]/=2,cnt--; ll ans=1; for(int i=0;i<3;i++) ans=mul(ans,fac[i]); fac.clear();cnt=1; fac.push_back(y+yy); fac.push_back(xx-x+1); fac.push_back(yy-y+1); for(int i=0;i<3;i++) if(cnt&&fac[i]%2==0)fac[i]/=2,cnt--; ll res=1; for(int i=0;i<3;i++) res=mul(res,fac[i]); (ans+=res)%=mod; ans-=mul(xx-x+1,yy-y+1)%mod; (ans+=mod)%=mod; printf("%lld\n",ans); /*ans=(x+xx)*(xx-x+1)%mod*(yy-y+1)%mod*inv%mod; ans+=(xx-x+1)*(y+yy)%mod*(yy-y+1)%mod*inv%mod;ans%=mod; ans-=(xx-x+1)*(yy-y+1)%mod;ans=(ans+mod)%mod; printf("%lld\n",ans);*/ return 0; }
B.分组配对
显然,最大 $\times$ 最大$+$ 第二大 $\times$ 第二大 $+...$的方式能使小组总值最大。
这里简单写一下证明,考虑只有两对的情况。
设它们为$a,b,a-x,b-y$,因为实力值为正整数所以必有$a>x,b>y$
那么按排名配对的总值为$ab\times 2 -ay-bx+xy$
交叉配对的为$ab \times 2 -ay-bx$
很显然前者大于后者。
所以只要贪心地往右扫,到不能加入组里时开新组就好了。
暴力的话每次都sort或二分查找肯定是不行的
由于往右扩展这个过程具有单调性,可以考虑二分
但check一次的代价也很大,需要设法减小二分范围
那么可以先倍增到一个不合法的位置,再以$1<<(p-1)$为左边界,$1<<p$为右边界进行二分
时间复杂度最劣为$O(n\ log^2 \ n)$。
#include<cstdio> #include<iostream> #include<cstring> #include<vector> #include<algorithm> using namespace std; typedef long long ll; ll read() { ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=5e5+5; int n; ll m; ll a[N],b[N]; vector<ll> nowa,nowb; bool check(int l,int r) { vector<ll> tmpa,tmpb; swap(nowa,tmpa);swap(nowb,tmpb); for(int i=l;i<=r;i++) nowa.push_back(a[i]),nowb.push_back(b[i]); sort(nowa.begin(),nowa.end());sort(nowb.begin(),nowb.end()); int sz=nowa.size();ll res=0; for(int i=sz-1;i>=0;i--) { res+=nowa[i]*nowb[i]; if(res>m)return 0; } return 1; } int find(int x) { int p=0; for(int i=0; ;i++) { p=i; if(!check(x,min(x+(1<<i)-1,n)))break; if(x+(1<<i)-1>=n)break; } int l=x+(1<<p-1)-1,r=min(x+(1<<p)-1,n),res=l; while(l<=r) { int mid=l+r>>1; if(check(x,mid))res=mid,l=mid+1; else r=mid-1; } return res; } #define F int main() { #ifdef F freopen("pair.in","r",stdin); freopen("pair.out","w",stdout); #endif n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) b[i]=read(); int ans=0; int i=1; while(i<=n)i=find(i)+1,ans++; printf("%d\n",ans); return 0; } /* 3 50 6 7 6 6 3 5 */
C.城市游戏
咕
兴许青竹早凋,碧梧已僵,人事本难防。