AGC 019

来源:互联网 发布:node readfilesync 编辑:程序博客网 时间:2024/05/16 11:35

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+1using 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 longusing 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 1e9using 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[i1][jk]Ckm(jk)k!Ck+1i+j 注意一条链是k+2个点,k+1次交换
化一下柿子,移项,得到
F[i][j]=k1(k+1)!F[i1][jk]
F[i]=F[i1]G
f[i][j]=F[i][j](i+j)!(mj)!
快速幂套个NTT,O(nlog2n)
ans=if[e][i]e!(mi)!(mi)!Cmie+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 longusing 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+12iCi2iCnin+m2iCmn+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 1e9using 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;}
原创粉丝点击