T1024
T1
爆零赛总是从T1做不出来开始
T1
题面:
古代龙人手中共有n粒秘药,我们可以用1表示「古老的秘药」,其余的用0表示。他将它们排成一列。古代龙人认为平衡是美的,于是他问Mark能选出多少个「平衡的区间」。「平衡的区间」是指首先选出一个区间[L, R],在它内部选出一个中间点mid,满足L<mid<R,mid是「古老的秘药」,且区间[L, mid]和[mid, R]中「古老的秘药」个数相等。
其实就是找出有多少个区间里面有奇数个\(1\)
那么我们可以先处理出每个\(1\)的左边有多少\(0\)
然后隔一个加一个求前缀和\(sum[]\)
然后\(O(n)\)枚举左端点,用它左边的\(0\)乘右边\(sum\)的和
代码如下:
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e6+10; int ts,n,a[maxn],cnt,rt[maxn]; ll sm[2],ans=0; int main() { scanf("%d%d",&ts,&n); for(int i=1;i<=n;i++) scanf("%1d",&a[i]),cnt+=a[i]; int sum=0; for(int i=n,j=cnt;i && j;i--){ sum++; if(a[i]){rt[j]=sum;sum=0;j--;} } for(int i=1;i<=cnt;i+=2) sm[1]+=rt[i]; for(int i=2;i<=cnt;i+=2) sm[0]+=rt[i]; sum=0; for(int i=1,j=1;i<=n;i++){ ++sum; if(a[i]){ ans+=(sum-1)*(rt[j]-1)+sum*(sm[j&1]-rt[j]); sm[j&1]-=rt[j];j++;sum=0; } } printf("%lld\n",ans); return 0; }
T2
T1都不会T2更降智
T2
题面:
数据范围特别小,二进制枚举或者爆搜前一半和后半选啥就行
代码如下:
#include<bits/stdc++.h> #define ll long long using namespace std; int n;ll ans=0; string s; map<string,ll> mp; int main() { scanf("%d",&n);cin>>s; for(int i=0;i<(1<<n);i++){ string s1,s2; for(int j=1;j<=n;j++){ if(i&(1<<(j-1))) s1+=s[j-1]; else s2+=s[j-1]; } mp[s1+'~'+s2]++; } for(int i=0;i<(1<<n);i++){ string s1,s2; for(int j=1;j<=n;j++){ if(i&(1<<(j-1))) s1=s[j+n-1]+s1; else s2=s[j+n-1]+s2; } ans+=mp[s2+'~'+s1]; } printf("%lld\n",ans/2); return 0; }
T3
咕