$whzzt$这个出题人我记住了。。。7场之前刚见过他。。。
目前做过的他出的$5$道题,得分$0+5+0+1+0$
怎么搞得跟满分$10$分一样。。。
得亏今天$T3$是原题。不然总分又是个位数。
一只老虎一棵蒜,爆零爆的团团转。
的确感觉$T2$比较简单,但神$**$的这居然是个结论题。
我在那里想了不知道多久做法,然而想了半天居然是个极其简单的结论(然而证明还挺奇怪
大神们都直觉秒结论。$66$分搜索拿$bitset$一压就没了。
然后我花了$3h$想方设法优化暴力算法,最后剪枝挂了$11 ightarrow 0$。
没办法了。这就是看命了。
结果被$T2$吃了大量时间而一无所获的我去看了下$T3$,发现好像可以比较直观的理解。
然而剩下的时间不多,于是暴写,一遍过样例,花了差不多半小时,就剩下$4$分钟,吓死我。
生死时速,$0pts$和$101pts$的区别。(有了最后$4min$才去把$T1$的签到拿下,然而$5pts$暴力没时间写了
T1:数学
大意:给定$a,n,b,m$满足$a^n equiv -1(mod m),b^n equiv -1 (mod m)$求$c$满足$c^2 equiv ab (mod m)$。多测。$T le 10000,n,m,a,b le 10^{18}$
大概是个构造公式的题。
老套路,想办法减小数据规模递归下去。
先考虑一些别的情况,如果$n$是奇数那么一个可行的答案就是$(ab)^{frac{n+1}{2}}$
如果$m$是偶数那么可以直接提出$2$。
如果$m$是$4$的倍数,那么显然不存在合法的$a,b$。不可能。
所以只要考虑$m$是奇数。
然后就是完全想不到的了,一堆设列公式:(题解还有锅
如果$y_0^{2w}=1$那么移项并且平方差得到$(y_0^{w}-1)(y_0^{w}+1) equiv 0$
然后$m$对二者分别取$gcd$。显然没有交,但是为什么并起来恰好是$m$就不得而知了。(题解也不说
然后就递归求解再$CRT$回来。复杂度是$O(Tlog^2m)$的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 ll mul(ll x,ll y,ll m,ll a=0){ 5 if(x<1<<30&&y<1<<30)return x*y%m; 6 for(;y;y>>=1,x<<=1,x=x>=m?x-m:x)if(y&1)a+=x,a=a>=m?a-m:a; 7 return a; 8 } 9 ll qp(ll b,ll t,ll m,ll a=1){for(;t;t>>=1,b=mul(b,b,m))if(t&1)a=mul(a,b,m);return a;} 10 ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} 11 void exgcd(ll a,ll b,ll&x,ll&y){ 12 if(!b){x=1;y=0;return;} 13 exgcd(b,a%b,y,x);y-=a/b*x; 14 } 15 ll inv(ll x,ll m){ll a,b;exgcd(x,m,a,b);return (a%m+m)%m;} 16 ll CRT(ll a,ll m,ll A,ll M){return (mul(mul(a,inv(M,m),m),M,m*M)+mul(mul(A,inv(m,M),M),m,m*M))%(m*M);} 17 ll solve(ll a,ll b,ll n,ll m){a%=m;b%=m; 18 if(n&1)return qp(mul(a,b,m),n+1>>1,m); 19 if(m<=2)return m-1; 20 if(m&1^1)return m>>=1,CRT(solve(a,b,n,2),2,solve(a,b,n,m),m); 21 ll N=n; int c=0; while(N&1^1)N>>=1,c++; 22 ll r=qp(a,N,m),c0=qp(mul(a,b,m),N+1>>1,m),y0=qp(mul(a,b,m),N,m); 23 vector<ll>pw(c+1); for(int i=0;i<=c;++i)pw[i]=r,r=mul(r,r,m); 24 while(c){ 25 int w=0; ll X; for(ll x=y0;x!=1;++w)X=x,x=mul(x,x,m); 26 w--; if(w<0)break; 27 if(X!=m-1){ll m1=gcd(m,X-1),m2=gcd(m,X+1);return CRT(solve(a,b,n,m1),m1,solve(a,b,n,m2),m2);} 28 c0=mul(c0,pw[c-w-1],m); y0=mul(y0,pw[c-w],m); 29 }return c0; 30 } 31 main(){ll a,b,n,m,t,id;cin>>t>>id;while(t--)scanf("%lld%lld%lld%lld",&a,&b,&n,&m),printf("%lld ",solve(a,b,n,m));}
T2:灌水
大意:给定数列$a$,求对于所有排列$p$的$sumlimits_{i=1}^{n} min(max(a_j[jle i]),max(a_j[j ge i])) -a_i$有哪些可能值。$n le 1000,a_i le 100$
结论是:对于每个$a_i$它都可能产生任意$a_j geq a_i$的$a_j > a_i$。(除了$a_j$是唯一最大值)。互不干扰可以直接叠加。
大概是可证的,就是可以通过交换二者位置。这种结论你猜不出来证它干啥。
然后这题就只剩下背包了。唯一需要想的就是需要$bitset$一下。复杂度$O(frac{n^2l^2}{32})$。
1 #include<bits/stdc++.h> 2 using namespace std; 3 bitset<100001>B,R; 4 int n,a[1111],y[111]; 5 int main(){ 6 cin>>n; 7 for(int i=1;i<=n;++i)scanf("%d",&a[i]),y[a[i]]++; 8 sort(a+1,a+1+n); reverse(a+1,a+n+1); y[a[1]]--; B=1; 9 for(int i=2;i<=n;++i){ 10 for(int j=a[i]+1;j<=100;++j)if(y[j])R|=B<<j-a[i]; 11 B|=R;R.reset(); 12 }for(int i=0;i<=100000;++i)if(B[i])printf("%d ",i); 13 }
T3:C
大意:环上等距有$n$个等质量质点。有些脱落了。求最少再脱落几个能使重心回到环中心。$n le 20000$。$n$最多有$2$种质因子。
$2$自然会是关键点。
按照重心的定义,发现重心是带权可加的。所以我们可以把整个环拆成若干集合,使每个集合的重心都在环中心就好。
只有$1$种质因子的话,编号模$frac{n}{p}$相同的点合并为一个集合一定是最优的。(其余合并方法均可以拆分)线性判断即可。
否则,每个点属于两个集合,但它同时只能存在于一个集合内,最大独立集,最大权闭合子图,没了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Sz 233333 4 int k,n,a,b,ban[Sz],A,B,S,T,BAN[Sz],q[Sz],d[Sz],fir[Sz],l[Sz],to[Sz],v[Sz],ec; 5 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;} 6 void con(int a,int b,int w){link(a,b,w);link(b,a,0);} 7 bool bfs(){ 8 for(int i=0;i<=T;++i)d[i]=Sz;d[S]=1;q[1]=S; 9 for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(d[to[i]]>d[q[h]]+1&&v[i]) 10 d[q[++t]=to[i]]=d[q[h]]+1; 11 return d[T]!=Sz; 12 } 13 int dfs(int p,int f){int r=f; 14 if(p==T)return f; 15 for(int i=fir[p];i&&r;i=l[i])if(d[to[i]]==d[p]+1&&v[i]){ 16 int x=dfs(to[i],min(r,v[i])); 17 if(!x)d[to[i]]=-1; 18 v[i]-=x;v[i^1]+=x;r-=x; 19 }return f-r; 20 } 21 int main(){int t;cin>>t;while(t--){ 22 23 cin>>n>>k; a=b=0; 24 int x=n; 25 for(int i=2;i*i<=x;++i)if(x%i==0){ 26 if(!b)a=i,A=n/a;else b=i,B=n/b; 27 while(x%i==0)x/=i; 28 break; 29 }if(x>1)if(!a)a=x,A=n/a;else b=x,B=n/b; 30 if(!b){ 31 int ans=0; 32 for(int i=0;i<A;++i)ban[i]=0; 33 for(int i=1,x;i<=k;++i)scanf("%d",&x),ban[(x-1)%A]=1; 34 for(int i=0;i<A;++i)ans+=ban[i]?0:a; 35 cout<<(ans?n-k-ans:-1)<<endl; 36 }else{ 37 S=A+B;T=S+1;int ans=0; 38 for(int i=0;i<A;++i)ban[i]=0; 39 for(int i=0;i<B;++i)BAN[i]=0; 40 for(int i=1,x;i<=k;++i)scanf("%d",&x),x--,ban[x%A]=1,BAN[x%B]=1; 41 ec=1; for(int i=0;i<=T;++i)fir[i]=0; 42 for(int i=0;i<A;++i)if(!ban[i])con(S,i,a),ans+=a; 43 for(int i=0;i<B;++i)if(!BAN[i])con(i+A,T,b),ans+=b; 44 for(int i=0;i<n;++i)con(i%A,A+i%B,Sz); 45 while(bfs())ans-=dfs(S,n); 46 cout<<(ans?n-k-ans:-1)<<endl; 47 } 48 49 }}