AGC 019

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[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 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+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 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值