2023.08.10杭电多校第八场

burutaofan / 2023-08-11 / 原文

solved:3

rank:

C.Congruences

题意:对于每组数据给定M个pi和qi,pi为两两不同的质数,N为所有pi的积,问是否存在最小的正整数x使得 x^pi在模N的意义下与qi同余,如果存在输出x,否则输出-1;

显然x^pi在模N的意义下与qi同余可以推出x^pi在模pi的意义下与qi同余,此外,由于pi为质数,故由费马小定理可得,x^pi在模pi的意义下与x同余,因此原问题可转化为给定M个pi和qi,问是否存在最小的正整数x使得x在模pi的意义下与qi同余 用中国剩余定理计算即可,注意要开int128;

又因x^pi^在模N的意义下与qi同余可以推出x^pi^在模pi的意义下与qi同余的逆命题不成立故在算出来结果后还需对每一组pi和qi判断是否成立;

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 typedef __int128_t int128; 
 5 ll read(){
 6     char ch=getchar();ll x=0,f=1;
 7     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 8     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 9     return x*f;
10 }
11 const int maxn=1000000+11;
12 ll T,M,N,x;
13 ll p[maxn],q[maxn];
14 ll p2[maxn],q2[maxn],t[maxn];
15 ll quickpow(int128 a,ll b,ll Mod){
16     ll ret=1;
17     while(b){
18         if(b&1)ret=(int128)ret*a%Mod;
19         a=(int128)a*a%Mod;
20         b>>=1;
21     }
22     return ret;
23 }
24 int main(){
25     T=read();
26     while(T--){
27         M=read();
28         N=1;x=0;
29         for(int i=1;i<=M;i++){
30             p[i]=read();q[i]=read();
31             N=N*p[i];q2[i]=q[i]%p[i];
32         }
33         for(int i=1;i<=M;i++)p2[i]=N/p[i];
34         for(int i=1;i<=M;i++){
35             t[i]=quickpow(p2[i],p[i]-2,p[i]);
36         }
37         for(int i=1;i<=M;i++){
38             x=(x+(((int128)q2[i]*p2[i])%N*t[i])%N)%N;
39         }
40         x=(x%N+N)%N;
41         if(x==0)x=N;
42         bool flag=true;
43         for(int i=1;i<=M;i++){
44             if(quickpow((int128)x,p[i],N)!=q[i]){
45                 cout<<"-1"<<endl;
46                 flag=false;
47                 break;
48             }
49         }
50         if(flag){
51             cout<<x<<endl;
52         }
53     }
54     return 0;
55 }

E.0 vs 1

题意:给定一串01串,0和1轮流从两端取,0只能取0,1只能取1,若取完为平局,否则0取到1 / 1取到0即输,两人都采取最优策略,问谁会获胜;

若两端字符不相同,两名玩家都只能直接选取,0输当且仅当串的两端都为1,且上一步中1已经取走了一个1,故必定存在一边有两个1,1输的情况同理(这题代码对着标程打的);

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read(){
 4     char ch=getchar();int x=0,f=1;
 5     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 6     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 7     return x*f;
 8 }
 9 const int maxn=1e5+5;
10 int T,N,L,R,now;
11 string s;
12 int A[maxn]; 
13 void firstcheck(){
14     while(L<R&&A[L]+A[R]==1){
15         if(A[L]==now)L++;
16         else R--;
17         now=1-now;
18     }
19     if(L==R&&A[L]==now)L++;
20 }
21 int checkleft(int now){
22     for(int i=L;i<=R;i++){
23         if(now!=A[i])return i;
24         now=1-now;
25     }
26     return -1;
27 }
28 int checkright(int now){
29     for(int i=R;i>=L;i--){
30         if(now!=A[i])return i;
31         now=1-now;
32     }
33     return -1;
34 }
35 int main(){
36     T=read();
37     while(T--){
38         N=read();
39         cin>>s;
40         for(int i=1;i<=N;i++)A[i]=s[i-1]-'0'; 
41         L=1,R=N,now=0;
42         firstcheck();
43         if(L>R){
44             cout<<"-1"<<endl;
45             continue;
46         }
47         if(A[L]!=now){
48             cout<<1-now<<endl;
49             continue;
50         }
51         int lpos=checkleft(now);
52         int rpos=checkright(now);
53         if((lpos!=-1&&A[lpos]==now)||(rpos!=-1&&A[rpos]==now)){
54             cout<<now<<endl;
55             continue;
56         }
57         if(rpos+1==lpos||lpos==-1){
58             cout<<"-1"<<endl;
59             continue;
60         }
61         cout<<A[lpos]<<endl;
62     }
63     return 0;
64 }

G.Solubility

题意:互溶关系具有传递性,给定一些互溶关系;询问一些液体,问是否互溶;

并查集维护即可;

 1 #include<bits/stdc++.h>
 2 using namespace std ;
 3 inline int read(){
 4     int s=1,w=0;
 5     char ch=getchar();
 6     while(ch<'0'||ch>'9'){if(ch=='-')s=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
 8     return s*w;
 9 }
10 int T,N,M,K;
11 int x,y;
12 int fa[100005];
13 int getfa(int x){
14     if(x==fa[x])return x;
15     return fa[x]=getfa(fa[x]);
16 }
17 void solve(){
18     N=read();M=read();
19     for(int i=1;i<=N;i++)fa[i]=i;
20     for(int i=1;i<=M;i++){
21         x=read();y=read();
22         fa[getfa(x)]=getfa(y);
23     }
24     K=read();
25     bool flag=true;
26     x=read();
27     int fx=getfa(x);
28     for(int i=2;i<=K;i++){
29         y=read();
30         if(fx!=getfa(y))flag=false;
31     }
32     if(flag)cout<<"YES"<<endl;
33     else cout<<"NO"<<endl;
34 }
35 int main() {
36     T=read();
37     while(T--){
38         solve();
39     }
40     return 0 ;
41 }

H.Expectation of Rank

题意:给定方阵的行数和列数N,以及一个素数P,问方阵在模P意义下的秩的期望值;

一共有N*N个位置可以选数,每个位置有P种选择(0~P-1),且由于P是质数,我们对于确定的一个行向量,任取0~P-1中的一个数乘行向量得到的新的向量是两两不同的;我们定义dp[i][j]为当前选了i个向量,秩为j时的方案数,有转移方程dp[i][j] = ( p^N - p^(j-1) ) * dp[ i-1 ] [ j-1 ] + ( p^j ) * dp[ i-1 ] [ j ];

因为与秩为j的向量组线性相关的向量共有p^j种(对于其极大线性无关组中的每一个向量前的系数可以在0~P-1中任取);

最后用 当前秩方案数*秩之和 乘上 总方案数的乘法逆元即可;

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int read(){
 5     char ch=getchar();int x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 const int Mod=1e9+7;
11 const int maxn=5e3+5;
12 int T,N,P;
13 ll dp[maxn][maxn];
14 ll p[maxn];
15 ll quickpow(ll a,ll b){
16     ll ret=1;
17     while(b){
18         if(b&1)ret=ret*a%Mod;
19         a=a*a%Mod;
20         b>>=1;
21     }
22     return ret;
23 }
24 ll solve(){
25     N=read();P=read();
26     p[0]=1;
27     for(int i=1;i<=N;i++){
28         p[i]=p[i-1]*P%Mod;
29     }
30     dp[0][0]=1;
31     for(int i=1;i<=N;i++){
32         dp[i][0]=1;
33         for(int j=1;j<=i;j++){
34             dp[i][j]=(p[N]-p[j-1]+Mod)%Mod*dp[i-1][j-1]%Mod+p[j]*dp[i-1][j]%Mod;
35             dp[i][j]%=Mod;
36         } 
37     }
38     ll ans=0;
39     for(int i=1;i<=N;i++){
40         ans+=i*dp[N][i]%Mod;
41         ans%=Mod;
42     }
43     for(int i=1;i<=N;i++){
44         for(int j=1;j<=i;j++){
45             dp[i][j]=0;
46         }
47         p[i]=0;
48     }
49     return ans%Mod*quickpow(quickpow(P,N*N),Mod-2)%Mod;
50 }
51 int main(){
52     T=read();
53     while(T--){
54         cout<<solve()<<endl;
55     }
56     return 0;
57 }

J.Rikka with Square Numbers

题意:给定两个数a,b,问经过最少多少次加减完全平方数的操作可以将a变成b

等价于询问经过多少次加减完全平方数的操作可以表示出abs(a - b),不妨令其等于d;

若d为完全平方数,显然只需一次操作;

此外,(x+1)^2-x^2=2x+1;故倘若d为奇数一定可以用两次操作表示出;

倘若d为偶数,设d可以表示成两个完全平方数的差,则有x^2-y^2=d,(x+y)*(x-y)=d;当x与y的奇偶性相同时,显然(x-y)与(x+y)都为偶数,故d是4的倍数时,可以两次操作表出;

枚举,判断d是否能用两个完全平方数的和表出,如果可以,也只需两次操作;

如果以上情况都不成立,我们可以通过一次操作先把其变成奇数,再通过两次操作表示,共计三次操作;

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll read(){
 5     char ch=getchar();ll x=0,f=1;
 6     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
 8     return x*f;
 9 }
10 ll T,A,B;
11 bool pd(ll x){
12     ll y=sqrt(x);
13     if(y*y==x)return true;
14     return false;
15 }
16 void solve(){
17     A=read();B=read();
18     ll d=max(A-B,B-A);
19     if(pd(d)){
20         cout<<"1"<<endl;
21         return ;
22     }
23     if(d%2==1){
24         cout<<"2"<<endl;
25         return ;
26     }
27     if(d%4==0){
28         cout<<"2"<<endl;
29         return ;
30     }
31     for(int i=1;i*i*2<=d;i++){
32         if(pd(d-i*i)){
33             cout<<"2"<<endl;
34             return ;
35         }
36     }
37     cout<<"3"<<endl;
38     return ;
39 }
40 int main(){
41     T=read();
42     while(T--){
43         solve();
44     }
45     return 0;
46 }