2022icpc网络赛(II)

A(费马小定理)

  • \(n<100\)的时候,用最后一行直接暴力
  • 否则考虑费马小定理:\(10^{p-1}\equiv 1\ (mod p)\),即步长为\(p-1\)时的和可以直接使用,利用\(p-1\)行计算即可
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
const int Maxn=100005;
const int inf=1e9;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
int n,b[110][110],pw[110];
void solve()
{
    n=read();
    rep(i,1,min(n,100)) rep(j,1,i) b[i][j]=read();
    int q=read();
    if(n<100)
    {
        while(q--)
        {
            int pw=1,p=read(),ans=0;
            dwn(i,n,1) (ans+=pw*(b[n][i]%p))%=p,(pw*=10)%=p;
            printf("%d\n",ans);
        }
        return ;
    }
    while(q--)
    {
        int p=read(),ans=0,r=p-1;
        pw[0]=1;rep(i,1,p) pw[i]=(pw[i-1]*10)%p;
        rep(i,1,r)
        {
            (ans+=pw[(n-i)%r]*(b[r][i]%p))%=p;
        }
        printf("%d\n",ans);
    }
}
int main()
{
    rep(T,1,read()) solve();
}

B(dp)

两种操作实际上是等价的,即问题为删去\(2i\)个数后的最大答案

\(f[i][j]\)表示前\(i\)个数中删了\(j\)个数的答案,枚举这一次删去数的个数转移

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int MAXN=2001001;
const ll inf=1e18;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
int n,a[110];
ll f[110][110];
inline ll sqr(ll x){return x*x;}
inline void chkmx(ll& a,ll b){a=max(a,b);}
int main()
{
    n=read();
    rep(i,1,n) a[i]=read();
    f[1][0]=0;
    rep(i,2,n) rep(j,0,i-2)
        rep(k,0,j) chkmx(f[i][j],f[i-k-1][j-k]+sqr(a[i]-a[i-k-1]));
    rep(i,1,n) 
    {
        int w=min(2*i,n-2);
        cout<<f[n][w]<<endl;
    }
}

E(构造)

  • \(k\)为奇数构造:k 232323
  • \(k\)为偶数构造:k x 3232,其中\(x\)为最小的与\(k\)互质的数
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
const int Maxn=100005;
const int inf=1e9;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
int n,m;
ll ans;
int main()
{
    n=read(),m=read();
    if(m&1) ans=m+(n/2)*2+(n-1)/2*3;
    else 
    {
        ans=m;
        for(int i=3;i<=10000;i+=2)
            if(__gcd(i,m)==1) {ans+=i;break;}
        ans+=(n-1)/2*2+(n-2)/2*3;
    }
    cout<<ans<<endl;
}

F(数位分解)

暴力求出两个点到根的链

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
const int Maxn=100005;
const int inf=1e9;
ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
ll k,x,y;
vector<ll> v1,v2;
void work(ll w,vector<ll> &v)
{
    if(w==0) {v.assign(1,0);return ;}
    v.clear();v.push_back(w);
    __int128 pw=1;
    while(pw<=w) pw*=k+1;
    pw/=k+1;
    while(pw)
    {
        if(w>=pw) 
        {
            w=(w-pw)/k;
            v.push_back(w);
        }
        pw/=k+1;
    }
    reverse(v.begin(),v.end());
    return ;
}
void solve()
{
    k=read(),x=read()-1,y=read()-1;
    work(x,v1);
    work(y,v2);
    ll ans=0;
    rep(i,0,min(v1.size(),v2.size())-1)
    {
        if(v1[i]!=v2[i]) break;
        else ans=v1[i];
    }
    printf("%lld\n",ans+1);
}
int main()
{
    rep(T,1,read()) solve();
}

G(组合数学)

由于区间之间仅有包含关系,递归算出每个子区间的答案后的方案数即为剩余独立变量个数的阶乘

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int MAXN=2001001;
const int inf=1e9;
const int MOD=1000000007;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
inline int mul(int a,int b){return (1LL*a*b)%MOD;}
inline void inc(int& a,int b){a=pls(a,b);}
inline void dec(int& a,int b){a=mns(a,b);}
int n,m,fac[MAXN],ifac[MAXN],inv[MAXN],tag[MAXN],ans=1;
vi ed[MAXN];
void init(int n=2e6)
{
    fac[0]=1;rep(i,1,n) fac[i]=mul(fac[i-1],i);
    inv[1]=1;rep(i,2,n) inv[i]=mul(inv[MOD%i],MOD-MOD/i);
    ifac[0]=1;rep(i,1,n) ifac[i]=mul(ifac[i-1],inv[i]);
}
void dfs(int l,int r)
{
    int x=l,cnt=0;
    for(;x<=r;++x)
    {
        if(!ed[x].empty())
        {
            int r=ed[x].back();
            ed[x].pop_back();
            dfs(x,r);
            x=r;
        }
        cnt++;
    }
    ans=mul(ans,fac[cnt]);
}
int main()
{
    init();
    n=read(),m=read();
    rep(i,1,m) {int a=read(),b=read();ed[a].push_back(b);}
    rep(i,1,n) sort(ed[i].begin(),ed[i].end());
    dfs(1,n);
    cout<<ans<<'\n';
}

J(搜索)

总状态很少,搜索即可

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
const int Maxn=100005;
const int inf=1e9;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
int n,a[Maxn],up[Maxn],down[Maxn];
int Dfs(int l,int r,int lst) {
    
    if(l>r) return 1;
    
    if(lst<a[l]&&lst<a[r]) {
        int cl=Dfs(l+1,r,a[l]);
        int cr=Dfs(l,r-1,a[r]);
        if((cl&cr)==0) return 1;
        else return 0;	
    }
    else if(lst<a[l]) {
        return up[l]&1;
    }
    else if(lst<a[r]) {
        return down[r]&1;
    }
    else return 0;
    
}

int main() {
    n=read();
    
    for(int i=1;i<=n;++i)
        a[i]=read();
    
    down[1]=1;
    for(int i=2;i<=n;++i) {
        down[i]=1;
        if(a[i]<a[i-1]) down[i]+=down[i-1];
    }
    up[n]=1;
    for(int i=n-1;i;--i) {
        up[i]=1;
        if(a[i]<a[i+1]) up[i]+=up[i+1];
    }
    int ans=Dfs(1,n,0);
    
    if(ans==1) cout<<"Alice\n";
    else cout<<"Bob\n";
    return 0;
}

K(状态压缩)

状压记录每个格子被圆弧染色的情况,有\(\pi/2\)\(\pi/3\)两种情况;同时记录矩阵染色的情况。最后扫一遍

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll md = 998244353;
ll poww(ll a, ll b)
{
    ll ans = 1;
    for (; b; b>>=1, a=a*a%md)
        if (b&1)
            ans = ans *a%md;
    return ans;
}

int dat[305][305];
void SETX(int x, int y, int z)
{
    dat[x+105][y+105] = z;
}
int GETX(int x, int y)
{
    return dat[x+105][y+105];
}
const int MINX = -102;
const int MAXX = 102;
void drawsqu(int x, int y)
{
    SETX(x, y, -1);
}
void drawcir(int x, int y, int t)
{
    int old = GETX(x, y);
    if (old == -2)
    {
        SETX(x, y, 1 << t);
    }
    else if (old != -1)
    {
        int oldinfo[4] = {old&1, (old>>1)&1, (old>>2)&1, (old>>3)&1};
        if (oldinfo[t])	return;
        if ( (t==0 && oldinfo[2]) || (t==1 && oldinfo[3])
            || (t==2 && oldinfo[0]) || (t==3 && oldinfo[1]) )
        {
            SETX(x, y, -1);
        }
        else
        {
            SETX(x, y, old | (1 << t));
        }
    }
}
/*0 down  1 rgt  2 up  3 lft*/
int bj[305][305][4];
void SETB(int x, int y, int p, int z)
{
    bj[x+105][y+105][p] = z;
}
int GETB(int x, int y, int p)
{
    return bj[x+105][y+105][p];
}
int n;
int ana, anb;
int main()
{
    
    int i, j;
    for (i=MINX; i<=MAXX; ++i)
    {
        for (j=MINX; j<=MAXX; ++j)
        {
            SETX(i, j, -2);
        }
    }
    scanf("%d", &n);
    for (i=1; i<=n; ++i)
    {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if (op == 1)
        {
            drawsqu(x-1, y-1);
            drawsqu(x-1, y);
            drawsqu(x, y-1);
            drawsqu(x, y);
        }
        else
        {
            drawcir(x-1, y-1, 0);
            drawcir(x-1, y, 1);
            drawcir(x, y, 2);
            drawcir(x, y-1, 3);
        }
    }
    for (i=MINX; i<=MAXX; ++i)
    {
        for (j=MINX; j<=MAXX; ++j)
        {
            int tp = GETX(i, j);
            if (tp == -1)
            {
                for (int k=0; k<=3; ++k)
                {
                    SETB(i, j, k, 1);
                }
            }
            else if (tp >= 0)
            {
                for (int k=0; k<=3; ++k)
                {
                    if ( (tp >> k) & 1 )
                    {
                        SETB(i, j, k, 1);
                        SETB(i, j, (k+1)%4, 1);
                    }
                }
            }
        }
    }
    for (i=MINX; i<=MAXX; ++i)
    {
        for (j=MINX; j<=MAXX; ++j)
        {
            if (j!=MINX && ( GETB(i, j, 2) ^ GETB(i, j-1, 0) ) )
            {
                ++ana;
            }
            if (i!=MINX && ( GETB(i, j, 3) ^ GETB(i-1, j, 1) ) )
            {
                ++ana;
            }
            int tp = GETX(i, j);
            if (tp >= 0)
            {
                int pc = __builtin_popcount(tp);
                if (pc == 1)
                {
                    anb = (anb + poww(2, md-2)) %md;
                }
                else if (pc == 2)
                {
                    anb = (anb + poww(3, md-2)) %md;
                }
                else
                {
                    puts("ERR");
                    exit(-1);
                }
            }
        }
    }
    printf("%d %d\n", ana, anb);
    return 0;
}

L(预处理)

考虑预处理所有前缀内的\(icpc\)数量,只需要减掉\([1,l-1]\)内的I,IC,ICP\([l,r]\)内的CPC,PC,C组合的情况,继而问题转化为求区间内CPC,PC数量。将所需前缀数组全部预处理出来即可

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;i++)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;i--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
const int MAXN=2001001;
const int inf=1e9;
const int MOD=998244353;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
int n,q,lv[MAXN],rv[MAXN];
int sumi[MAXN],sumc[MAXN],sump[MAXN];
int ic[MAXN],icp[MAXN],cp[MAXN],pc[MAXN],icpc[MAXN],cpc[MAXN];
char s[MAXN];
inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
inline int mul(int a,int b){return (1LL*a*b)%MOD;}
inline void inc(int& a,int b){a=pls(a,b);}
inline void dec(int& a,int b){a=mns(a,b);}
int calc_pc(int l,int r)
{
    return mns(mns(pc[r],pc[l-1]),mul(sump[l-1],sumc[r]-sumc[l-1]));
}
int calc_cpc(int l,int r)
{
    int res=mns(cpc[r],cpc[l-1]);
    dec(res,mul(sumc[l-1],calc_pc(l,r)));
    dec(res,mul(cp[l-1],sumc[r]-sumc[l-1]));
    return res;
}
int main()
{
    n=read(),q=read();
    scanf("%s",s+1);
    rep(i,1,n) 
    {
        sumi[i]=sumi[i-1],
        sumc[i]=sumc[i-1],
        sump[i]=sump[i-1];
        if(s[i]=='I') sumi[i]++;
        else if(s[i]=='C') sumc[i]++;
        else sump[i]++;
    }
    rep(i,1,n)
    {
        ic[i]=ic[i-1],cp[i]=cp[i-1],pc[i]=pc[i-1];
        if(s[i]=='C') (ic[i]+=sumi[i-1])%=MOD,(pc[i]+=sump[i-1])%=MOD;
        if(s[i]=='P') (cp[i]+=sumc[i-1])%=MOD;
    }
    rep(i,1,n)
        icp[i]=(icp[i-1]+(s[i]=='P')*ic[i-1])%MOD,
        cpc[i]=(cpc[i-1]+(s[i]=='C')*cp[i-1])%MOD;
    rep(i,1,n) icpc[i]=(icpc[i-1]+(s[i]=='C')*icp[i-1])%MOD;
    int x=read(),a=read(),b=read(),p=read(),tot=0;
    rep(i,1,q) x=(1LL*a*x+b)%p,lv[i]=x%n+1;
    rep(i,1,q) x=(1LL*a*x+b)%p,rv[i]=x%n+1;
    rep(i,1,q) 
    {
        int l=lv[i],r=rv[i],ans=0;
        if(l>r) swap(l,r);
        ans=mns(icpc[r],icpc[l-1]);
        dec(ans,mul(sumi[l-1],calc_cpc(l,r)));
        dec(ans,mul(ic[l-1],calc_pc(l,r)));
        dec(ans,mul(icp[l-1],sumc[r]-sumc[l-1]));
        inc(tot,ans);
    }
    cout<<tot<<endl;
}
posted @ 2022-09-28 23:37  jack_yyc  阅读(91)  评论(0编辑  收藏  举报