codeforces #539 div1 做题记录

A.

考虑前一半异或和等于后一半可以转化为子串异或和为0

然后就做个前缀和,统计奇偶相同的有多少前缀和相同

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 300005
 4 using namespace std;
 5 int n;
 6 int a[maxn],s[maxn];
 7 map<int,int> mp1,mp2;
 8 int main()
 9 {
10     scanf("%d",&n);
11     for(int i=1;i<=n;++i)scanf("%d",&a[i]),s[i]=s[i-1]^a[i];
12     for(int i=0;i<=n;++i)
13     {
14         if(i&1)mp1[s[i]]++;
15         else mp2[s[i]]++;
16     }
17     map<int,int>::iterator it;
18     ll ans=0;
19     for(it=mp1.begin();it!=mp1.end();++it)
20     {
21         ll x=it->second;
22         ans+=x*(x-1)/2;
23     }
24     for(it=mp2.begin();it!=mp2.end();++it)
25     {
26         ll x=it->second;
27         ans+=x*(x-1)/2;
28     }
29     cout<<ans<<endl;
30     return 0;
31 }
View Code

B.

考虑一个显然的性质:

因为原串回文,所以从对称位置切,然后调换前后两段,cut次数不超过2(Impossible除外)

然后我们考虑是否有比2更小的答案1;

枚举每个位置暴力判判就行了;

 1 #include<bits/stdc++.h>
 2 #define maxn 5005
 3 using namespace std;
 4 char s[maxn],s2[maxn];
 5 bool ispalindrome()
 6 {
 7     int len=strlen(s2+1);
 8     for(int i=1;i<=len;++i)if(s2[i]!=s2[len-i+1])return 0;
 9     return 1;
10 }
11 int main()
12 {
13     scanf("%s",s+1);
14     int n=strlen(s+1);
15     int ans=n;
16     for(int i=n/2+((n&1)?1:0);i<=n;++i)
17     {
18         memset(s2,0,sizeof(s2));
19         int j=n-i;
20         int cnt=0;
21         for(int k=1;k<=j;++k)s2[++cnt]=s[i+k];
22         for(int k=j+1;k<=i;++k)s2[++cnt]=s[k];
23         for(int k=i+1;k<=n;++k)s2[++cnt]=s[k-i];
24         int t=2;
25         if(i==j)t=1;
26         if((strcmp(s+1,s2+1)!=0)&&(ispalindrome()))ans=min(ans,t);
27     }
28     for(int i=1;i<=n;++i)
29     {
30         memset(s2,0,sizeof(s2));
31         int cnt=0;
32         for(int j=i;j<=n;++j)s2[++cnt]=s[j];
33         for(int j=1;j<i;++j)s2[++cnt]=s[j];
34         int t=1;
35         if((strcmp(s+1,s2+1)!=0)&&(ispalindrome()))ans=min(ans,t);
36     }
37     if(ans==n)puts("Impossible");
38     else printf("%d\n",ans);
39     return 0;
40 }
View Code

C.

扫描二维码关注公众号,回复: 5227164 查看本文章

码码码题,留坑

D.

计数题

考虑枚举a,b之间有多少条边,记边数为e;

然后相当于我们在把长度m分成e份,每份为正,这个就是隔板,C(m-1,e-1)

然后考虑中间的点,方案是A(n-2,e-1)

然后考虑其他的点怎么放,这个等价于n个点构成森林,其中有e+1个点两两不处于同一个连通块,由Cayley定理,方案数是f(n,e+1)

其中f(x,y)=y*pow(x,x-y-1)

注意e==n-1时特判,此时方案数为1

最后考虑其他的边,乱选就行,pow(m,n-1-e)

乘上就是最终答案

 1 #include<bits/stdc++.h>
 2 #define maxn 1000005
 3 #define ll long long
 4 using namespace std;
 5 const ll mod = 1000000007;
 6 ll n,m,s,t;
 7 ll fac[maxn],invfac[maxn];
 8 ll fastpow(ll a,ll p)
 9 {
10     ll ans=1;
11     while(p)
12     {
13         if(p&1)ans=ans*a%mod;
14         a=a*a%mod;p>>=1;
15     }
16     return ans;
17 }
18 ll A(ll x,ll y)
19 {
20     return fac[x]*invfac[x-y]%mod;
21 }
22 ll C(ll x,ll y)
23 {
24     return fac[x]*invfac[y]%mod*invfac[x-y]%mod;
25 }
26 ll f(ll x,ll y)
27 {
28     if(x==y)return 1;
29     return y*fastpow(x,x-y-1)%mod;
30 }
31 int main()
32 {
33     cin>>n>>m>>s>>t;
34     fac[0]=1;
35     for(int i=1;i<=1000000;++i)fac[i]=fac[i-1]*i%mod;
36     for(int i=0;i<=1000000;++i)invfac[i]=fastpow(fac[i],mod-2);
37     ll ans=0;
38     for(int e=1;e<=n-1;++e)if(m>=e)
39     {
40         ans+=A(n-2,e-1)*f(n,e+1)%mod*C(m-1,e-1)%mod*fastpow(m,n-e-1)%mod;
41         ans%=mod;
42     }
43     cout<<ans<<endl;
44     return 0; 
45 }
View Code

猜你喜欢

转载自www.cnblogs.com/uuzlove/p/10402394.html