A
贪心搞一下就行了吧
B
如果翻转的一段串i~j,有s[i]=s[j](两端相等,那么他翻转的效果和i+1~j-1是一样的,所以我们只对s[i]≠s[j]的段i~j翻转,手玩一下发现翻转的结果一定是互不相同的,所以就统计一下有多少对(i,j)满足i< j且s[j]≠s[j],加上原串就是答案
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9+1
using namespace std;
const int maxn = 210000;
int n;
char str[maxn];
int sum[30];
ll ans;
int main()
{
scanf("%s",str); n=strlen(str);
ans=1;
for(int i=0;i<n;i++)
{
ans+=(ll)i-sum[str[i]-'a'];
sum[str[i]-'a']++;
}
printf("%lld\n",ans);
return 0;
}
C
首先没有必要为了不走或少走半圆而绕格子,容易发现这样不会更优(每行每列只有一个喷泉
所以在无视喷泉的情况下我们一定是挑某一条起点到终点的最短路
然后我们目的是使在(sx,sy)到(ex,ey)的路径上经过的1/4个环尽可能多,1/2个环尽可能少
对于1/4个环,按行(或列)排序后发现找个LIS就完事了,这样肯定是最多的
同时可以构造一下走法,发现只有LIS长度=起点和终点间的行数或列数时,一定要走1个1/2的环,特判一下
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210000;
const double pi = acos(-1);
int n;
struct node{int x,y;}a[maxn]; int cnt;
inline bool cmp(const node x,const node y){return x.x<y.x;}
int sx,sy,ex,ey;
int t[maxn],tp;
int main()
{
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
bool tx=false,ty=false;
if(sx>ex) swap(sx,ex),tx=true;
if(sy>ey) swap(sy,ey),ty=true;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y; scanf("%d%d",&x,&y);
if(sx<=x&&x<=ex&&sy<=y&&y<=ey) a[++cnt]=(node){x,y};
}
for(int i=1;i<=cnt;i++)
{
if(tx) a[i].x=sx+(ex-a[i].x);
if(ty) a[i].y=sy+(ey-a[i].y);
}sort(a+1,a+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
{
if(!tp) t[++tp]=a[i].y;
else
{
int l=1,r=tp;
while(l<=r)
{
int mid=l+r>>1;
if(t[mid]<a[i].y) l=mid+1;
else r=mid-1;
}++r;
t[r]=a[i].y; if(t[tp+1]) ++tp;
}
}
double ans=100.0*(ex-sx+ey-sy)+5*pi*tp-20.0*tp;
if(tp==ex-sx+1||tp==ey-sy+1) ans+=5*pi;
printf("%.15lf\n",ans);
return 0;
}
D
考虑最后和B串匹配的A串,是原来的A串左旋或右旋若干个单位得到的,右旋的我们可以将两个串都反过来做左旋,所以这里我们只考虑左旋
对于A串某个位置p,左旋i个单位后与B串的位置r对应,如果他和r位置不同,就一定对他需要至少一次filp操作,同时,如果他在转的过程中没有遇到B串的1,我们需要在左旋到目标位置后再左旋或旋之前右旋使他遇到某个B串为1的位置,分别记需要额外旋转left,right次
那么就是对每个这样的位置选择left or right使得(maxleft+maxright)*2最小
排个序弄个后缀max搞一下
复杂度n^2logn
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
inline void up(int &x,const int &y){if(x<y)x=y;}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 11000;
int n;
char s1[maxn],s2[maxn];
int pre1[maxn],pre2[maxn],topre[maxn],nex[maxn];
int cal(const int x,const int y)
{
if(x<y) return pre2[x]+pre2[n]-pre2[y-1];
else return pre2[x]-pre2[y-1];
}
int find_pre(const int x)
{
if(topre[x]) return x-topre[x];
else return x+n-topre[n];
}
int find_nex(const int x)
{
if(nex[x]!=n+1) return nex[x]-x;
else return nex[1]+n-x;
}
struct node{int left,right;}t[maxn]; int tp,mx[maxn];
inline bool cmp(const node x,const node y){return x.left<y.left;}
int solve()
{
int re=inf;
for(int i=0;i<n;i++)
{
int now=0; tp=0;
for(int j=1;j<=n;j++)
{
int r=j-i<=0?j-i+n:j-i;
if(s1[j]!=s2[r])
{
now++;
if(s1[j]=='0') continue;
if(cal(j,r)==0) t[++tp]=(node){find_pre(r),find_nex(j)};
}
}
sort(t+1,t+tp+1,cmp);
int cost; mx[tp+1]=0;
for(int j=tp;j>=1;j--) mx[j]=max(mx[j+1],t[j].right);
cost=mx[1]*2;
for(int j=1;j<=tp;j++)
{
int k=j+1;for(;k<=tp&&t[k].left==t[j].left;k++);k--;
down(cost,2*(t[j].left+mx[k+1]));
j=k;
}
if(!tp) cost=0;
down(re,now+cost+i);
}
return re;
}
int main()
{
scanf("%s",s1+1); scanf("%s",s2+1); n=strlen(s1+1);
for(int i=1;i<=n;i++)
pre1[i]=pre1[i-1]+(s1[i]-'0'),
pre2[i]=pre2[i-1]+(s2[i]-'0');
for(int las=0,i=1;i<=n;i++)
{
if(s2[i]=='1') las=i;
topre[i]=las;
}
for(int las=n+1,i=n;i>=1;i--)
{
if(s2[i]=='1') las=i;
nex[i]=las;
}
if(pre1[n]&&!pre2[n]) {puts("-1");return 0;}
int ans=solve();
for(int i=1;i*2<=n;i++)
swap(s1[i],s1[n-i+1]),
swap(s2[i],s2[n-i+1]);
for(int i=1;i<=n;i++)
pre1[i]=pre1[i-1]+(s1[i]-'0'),
pre2[i]=pre2[i-1]+(s2[i]-'0');
for(int las=0,i=1;i<=n;i++)
{
if(s2[i]=='1') las=i;
topre[i]=las;
}
for(int las=n+1,i=n;i>=1;i--)
{
if(s2[i]=='1') las=i;
nex[i]=las;
}
down(ans,solve());
printf("%d\n",ans);
return 0;
}
E
假设已经匹配好了(ai,bi),我们来计算合法的交换方案
对应到一个n个点的有向图上,每一对匹配,连边ai->bi
发现根据度数分类图中有4类点,对应AB串是00,01,10,11
图中不同的联通块,交换次序互不影响
对于每个联通块,只有3种情况
若它是孤立的点,对答案无影响
若它是一个环,交换顺序任意,因为始终是1和1交换
若它是一条链,只有一种交换顺序
我们记01点和10点的数量为e,11点的数量为m
图中一定会有e条链,若干个由11点组成的环
令f[i][j]表示j个11点分到i条链的方案数
有
f[i][j]=∑kf[i−1][j−k]∗Ckm−(j−k)∗k!∗Ck+1i+j
注意一条链是k+2个点,k+1次交换
化一下柿子,移项,得到
F[i][j]=∑k1(k+1)!F[i−1][j−k]
F[i]=F[i−1]∗G
f[i][j]=F[i][j]∗(i+j)!(m−j)!
快速幂套个NTT,
O(nlog2n)
ans=∑if[e][i]∗e!∗(m−i)!∗(m−i)!∗Cm−ie+m
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110000;
const ll Mod = 998244353;
ll pw(ll x,ll k)
{
ll re=1ll;
for(;k;k>>=1,x=x*x%Mod)
if(k&1) re=re*x%Mod;
return re;
}
ll si[maxn],sN[maxn],Ni[maxn];
void pre()
{
si[0]=1ll;for(ll i=1;i<maxn;i++) si[i]=si[i-1]*i%Mod;
sN[maxn-1]=pw(si[maxn-1],Mod-2);
for(ll i=maxn-2;i>=0;i--) sN[i]=sN[i+1]*(i+1)%Mod;
for(ll i=1;i<maxn;i++) Ni[i]=sN[i]*si[i-1]%Mod;
}
ll C(const int i,const int j){return si[i]*sN[j]%Mod*sN[i-j]%Mod;}
int N,ln;
ll g[maxn]; int id[maxn];
void DFT(ll s[],int sig,int nown)
{
for(int i=0;i<nown;i++) if(i<id[i]) swap(s[i],s[id[i]]);
int kk=N/nown;
for(int m=2;m<=nown;m<<=1)
{
int t=m>>1,tt=nown/m;
for(int j=0;j<nown;j+=m)
{
for(int i=0;i<t;i++)
{
ll wn=sig==1?g[i*tt*kk]:g[(nown-i*tt)*kk];
ll tx=s[j+i],ty=s[j+i+t]*wn%Mod;
s[j+i]=(tx+ty)%Mod;
s[j+i+t]=(tx-ty+Mod)%Mod;
}
}
}
if(sig==-1) for(int i=0;i<nown;i++) (s[i]*=Ni[nown])%=Mod;
}
ll f[maxn];
int n,m,e;
void FFT(ll s[])
{
//for(int i=0;i<N;i++) printf("%lld ",s[i]); puts("");
DFT(s,1,N);
for(int i=0;i<N;i++) s[i]=s[i]*s[i]%Mod;
DFT(s,-1,N);
//for(int i=0;i<N;i++) printf("%lld ",s[i]); puts("");
for(int i=m+1;i<N;i++) s[i]=0;
}
ll temp[maxn];
void get_f(ll f[],int k)
{
temp[0]=si[m];
for(;k;k>>=1,FFT(f)) if(k&1)
{
DFT(temp,1,N); DFT(f,1,N);
for(int i=0;i<N;i++) temp[i]=temp[i]*f[i]%Mod;
DFT(temp,-1,N); DFT(f,-1,N);
for(int i=m+1;i<N;i++) temp[i]=0;
}
for(int i=0;i<N;i++) f[i]=temp[i];
}
void solve()
{
for(int i=0;i<N;i++) id[i]=(id[i>>1]>>1)|((i&1)<<ln-1);
get_f(f,e);
}
char s1[maxn],s2[maxn];
int main()
{
pre();
scanf("%s%s",s1,s2); n=strlen(s1);
for(int i=0;i<n;i++)
{
if(s1[i]-'0'+s2[i]-'0'==1) e++;
else if(s1[i]-'0'+s2[i]-'0'==2) m++;
}e>>=1;
N=1,ln=0;
while(N<=2*m) N<<=1,ln++;
g[0]=1ll; g[1]=pw(3ll,(Mod-1)/N);
for(int i=2;i<=N;i++) g[i]=g[i-1]*g[1]%Mod;
for(int i=0;i<=m;i++) f[i]=sN[i+1];
solve();
ll ans=0;
for(int i=0;i<=m;i++)
(ans+=f[i]*si[e]%Mod*sN[m-i]%Mod*si[e+i]%Mod*si[m-i]%Mod*si[m-i]%Mod*C(e+m,m-i)%Mod)%=Mod;
printf("%lld\n",ans);
return 0;
}
F
wxh太强辣 http://blog.csdn.net/wxh010910/article/details/77752687
最优策略肯定是哪种剩下的多答哪种,将问题抽象在二维平面上,由(n,m)走到(0,0)
不妨设n>=m,发现当路径与y=x(x>0)不相交时一定是答对n个,
若相交,每次在交点时有1/2的概率得到1的增量,并且除去所有增量这条路径答案仍是n,
于是答案是
n+12∑iCi2i∗Cn−in+m−2iCmn+m)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
const ll Mod = 998244353;
const int maxn = 1010000;
ll pw(ll x,ll k)
{
ll re=1ll;
for(;k;k>>=1,x=x*x%Mod) if(k&1)
re=re*x%Mod;
return re;
}
int n,m;
ll s[maxn],invs[maxn],inv[maxn];
void pre()
{
s[0]=1ll;
for(ll i=1;i<maxn;i++) s[i]=s[i-1]*i%Mod;
invs[maxn-1]=pw(s[maxn-1],Mod-2);
for(ll i=maxn-2;i>=0;i--) invs[i]=invs[i+1]*(i+1)%Mod;
}
ll C(const int i,const int j){return s[i]*invs[j]%Mod*invs[i-j]%Mod;}
int main()
{
pre();
scanf("%d%d",&n,&m);
if(n<m) swap(n,m);
ll ans=0;
for(int i=1;i<=m;i++) (ans+=C(2*i,i)*C(n-i+m-i,n-i)%Mod)%=Mod;
ll inv=pw(C(n+m,m),Mod-2);
ans=ans*invs[2]%Mod*inv%Mod;
(ans+=n)%=Mod;
printf("%lld\n",ans);
return 0;
}