2022ccpc网络赛

一坨*这个人

全队都犯病了,没啥好说的

A(签到 模拟)

签到题

#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;
int num=0;
int cnt[4][15];
int readx()
{
    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();}
    cnt[num][x]++;
    if(ch=='\n') num++;
    if(num==4) return 0;
    return 1;
}
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;
}
vi deck,tmp;
int main()
{
    while(readx());
    int m=read(),val,cur=0;char s[5];
    while(m--)
    {
        scanf("%s",s+1);
        if(s[1]=='S') val=read();
        if(s[1]!='?')
        {
            int k=read();
            for(auto x:tmp) deck.push_back(x);
            tmp.clear();
            rep(i,1,k) {int x=read();tmp.push_back(x);cnt[cur][x]--;}
        }
        else 
        {
            int flg=1;
            for(auto x:tmp) if(x!=val) flg=0;
            int id=flg?cur:(cur+3)%4;
            for(auto x:tmp) cnt[id][x]++;
            for(auto x:deck) cnt[id][x]++;
            deck.clear();tmp.clear();
        }
        cur=(cur+1)%4;
    }
    rep(i,0,3) {rep(j,1,13) rep(k,1,cnt[i][j]) cout<<j<<' ';puts("");}
}

C(简单结论)

奇数因子显然无意义,手动模拟几轮之后容易得到规律

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        ll i = 0;
        __int128 j = 1;
        while (true)
        {
            ++i;
            j *= 2;
            if (b %j != 0)
            {
                printf("%lld %lld\n", i, 0LL);
                break;
            }
            j *= 2;
            if (a %j != 0)
            {
                printf("%lld %lld\n", i, 1LL);
                break;
            }
        }
    }
    return 0;
}

E(dp)

由于模式串中大写字母很少,直接暴力匹配dp即可,复杂度为\(O(200|S|)\)

\(f[i][j]\)表示模式串匹配到第\(i\)个大写字母,匹配串匹配到\(j\)位时匹配串匹配的最长长度,分两种情况转移即可:

  • 当前大写字母与模式串\(j\)位相同,从\(f[i][j-1]+1\)转移
  • 上一个大写字母之间的小写字符串与\(t(j-len+1,j)\)相同,从\(f[i-1][j-len]+len\)转移,用哈希判断字符串相等即可
#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 double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
const int inf=1e9;
inline 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;
}
const int MOD=1000000007,bas=233;
inline int mul(int a,int b){return 1LL*a*b%MOD;}
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;}
int n,m,hsh[MAXN],pw[MAXN];
int f[210][MAXN];
char s[MAXN],t[MAXN];
vi pos,val;
inline int getw(int l,int r){return mns(hsh[r],mul(hsh[l-1],pw[r-l+1]));}
void solve()
{
    scanf("%s%s",s+1,t+1);
    n=strlen(s+1),m=strlen(t+1);
    pw[0]=1;rep(i,1,n) hsh[i]=pls(mul(hsh[i-1],bas),s[i]-'a'+1),pw[i]=mul(pw[i-1],bas);
    pos.clear();val.clear();
    pos.push_back(0);val.push_back(0);
    int x=0;
    rep(i,1,m+1) 
        if(i==m+1||isupper(t[i])) 
        {
            pos.push_back(i);val.push_back(x);
            t[i]=t[i]-'A'+'a';
            x=0;
        }
        else x=pls(mul(x,bas),t[i]-'a'+1);
    m=pos.size()-1;
    int ans=0;
    rep(i,1,m) rep(j,0,n)
    {
        f[i][j]=-inf;
        if(j&&t[pos[i]]==s[j]) f[i][j]=f[i][j-1]+1;
        int len=pos[i]-pos[i-1]-1;
        if(j>=len&&(!len||getw(j-len+1,j)==val[i]))
            f[i][j]=max(f[i][j],f[i-1][j-len]+len);
        if(i==m) ans=max(ans,f[i][j]);
    }
    printf("%d\n",ans);
}
int main()
{
    rep(T,1,read()) solve();
}

G(记忆化搜索)

对正反串分别建立trie树,令\(f[x][y]\)表示在两个树的\(x,y\)节点上的最长匹配长度,当点对被重复访问时说明出现了循环,答案为inf

使用dfs转移(注意考虑串的结尾向trie树根的转移

#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 double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline 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;
}
struct trie
{
    int tr[5050][26],tot,ed[5050];
    trie():tot(0){memset(tr,0,sizeof(tr));memset(ed,0,sizeof(ed));}
    void ins(char *s,int len)
    {
        int pos=0,ch;
        rep(i,0,len-1)
        {
            ch=s[i]-'a';
            if(!tr[pos][ch]) tr[pos][ch]=++tot;
            pos=tr[pos][ch];
        }
        ed[pos]|=1;
    }
}t1,t2;
int n,f[5050][5050],ans,cnt=0;
char s[5050];
void dfs(int x,int y)
{
    if(t1.ed[x]&&t2.ed[y]) {puts("INF");exit(0);}
    ans=max(ans,f[x][y]);
    rep(i,0,25)
    {
        if(t1.tr[x][i]&&t2.tr[y][i])
        {
            if(~f[t1.tr[x][i]][t2.tr[y][i]]) {puts("INF");exit(0);}
            f[t1.tr[x][i]][t2.tr[y][i]]=f[x][y]+1;
            dfs(t1.tr[x][i],t2.tr[y][i]);
        }
        if(t1.ed[x]&&t1.tr[0][i]&&t2.tr[y][i])
        {
            if(~f[t1.tr[0][i]][t2.tr[y][i]]) {puts("INF");exit(0);}
            f[t1.tr[0][i]][t2.tr[y][i]]=f[x][y]+1;
            dfs(t1.tr[0][i],t2.tr[y][i]);
        }
        if(t2.ed[y]&&t2.tr[0][i]&&t1.tr[x][i])
        {
            if(~f[t1.tr[x][i]][t2.tr[0][i]]) {puts("INF");exit(0);}
            f[t1.tr[x][i]][t2.tr[0][i]]=f[x][y]+1;
            dfs(t1.tr[x][i],t2.tr[0][i]);
        }
    }
}
int main()
{
    n=read();
    rep(i,1,n)
    {
        scanf("%s",s);int len=strlen(s);
        t1.ins(s,len);
        reverse(s,s+len);
        t2.ins(s,len);
    }
    rep(i,0,t1.tot) rep(j,0,t2.tot)	f[i][j]=-1;
    f[0][0]=0;
    dfs(0,0);
    cout<<ans<<'\n';
}

H(pollard rho)

简单推一下式子容易发现\(x\)一定是\(K\)的因子,而因子数实际上很小,用\(pollard\ rho\)得到\(K\)的所有质因子,再暴力组合枚举所有因子,复杂度为\(O(K^{\frac{1}{4}})\)

对于每个\(x\)暴力判断即可

#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 double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline 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 ll mul(ll a,ll b,ll mod){return (__int128)a*b%mod;}
ll qp(ll x,ll t,ll mod,ll res=1)
{
    for(;t;t>>=1,x=mul(x,x,mod))
        if(t&1) res=mul(res,x,mod);
    return res;
}
bool miller_rabin(ll n)
{
    if(n==1) return 0;
    if(n<=3) return 1;
    ll m=n-1,b=0;
    while(!(m&1)) m>>=1,b++;
    rep(i,1,15)
    {
        ll x=qp(rand()%(n-2)+2,m,n);
        if(x==1||x==n-1) continue;
        rep(i,1,b-1) {x=mul(x,x,n);if(x==n-1) break;}
        if(x!=n-1) return 0;
    }
    return 1;
}
ll pollard_rho(ll n)
{
    ll s=0,t=0,c=rand()%(n-1)+1,val=1;
    for(int lim=1;;lim*=2,s=t,val=1) rep(i,1,lim)
    {
        t=(mul(t,t,n)+c)%n;
        val=mul(val,abs(t-s),n);
        if(i%127==0||i==lim)
        {
            ll d=__gcd(val,n);
            if(d>1) return d;
        }
    }
}
vector<ll> fac,ans;
void getFac(ll n)
{
    if(n==1) return ;
    if(miller_rabin(n)) {fac.push_back(n);return ;}
    ll m=n;
    while(m==n) m=pollard_rho(n);
    while(n%m==0) n/=m;
    getFac(n);getFac(m);
}
ll L,R,K;
int len;
bool check(ll x)
{
    ll a=(L+x-1)/x,b=R/x,m=b-a+1;
    if(m>=50) return 0;
    ll y=(1LL<<m-1)*(b+a)*m/2;
    return y==K/x;
}
void dfs(int i,ll now,ll n)
{
    if(i==len) {if(check(now)) ans.push_back(now);return ;}
    dfs(i+1,now,n);
    while(n%fac[i]==0)
    {
        now*=fac[i],n/=fac[i];
        dfs(i+1,now,n);
    }
}
void solve()
{
    scanf("%lld%lld%lld",&L,&R,&K);
    fac.clear();ans.clear();
    getFac(K);
    sort(fac.begin(),fac.end());
    fac.erase(unique(fac.begin(),fac.end()),fac.end());
    len=fac.size();
    dfs(0,1,K);
    if(ans.empty()) {puts("No Solution");return;}
    printf("%d\n",(int)ans.size());
    sort(ans.begin(),ans.end());
    for(auto x:ans) printf("%lld%c",x," \n"[x==ans.back()]);
}
int main()
{
    rep(T,1,read()) solve();
}

I(差分)

不妨令所有\(a_i<b_i\),考虑将传送门建在\((x,y),x<y\) 两个位置的答案:

\[\begin{aligned} ans(x,y)&=\sum\limits_{i=1}^mv_i\cdot\min\left\{|a_i-b_i|,\ |x-a_i|+|y-b_i|\right\}\\ &=\sum\limits_{i=1}^m(b_i-a_i)v_i+\sum\limits_{i=1}^mv_i\cdot \min\left\{0,\ |x-a_i|+|y-b_i|-(b_i-a_i)\right\} \end{aligned}\]

考虑固定\(x\),根据\(x\)\(a_i\)的大小关系,\(\min\)部分可以写为:

\[\begin{cases} \min\left\{0,2a_i-b_i-x+|y-b_i|\right\}&x<a_i\\ \\ \min\left\{0,x-b_i+|y-b_i|\right\}&x\ge a_i \end{cases}\]

\(2a_i-b_i-x\)\(x-b_i\)记为\(w\),显然仅当\(w<0\)时,\(\min\)才有意义

固定\(x\),利用二阶差分,对于每个运输计划在\(b_i-|w|+1,\ b_i+1,\ b_i+|w|+1\)处分别标记,求关于\(y\)的函数值,这样得到了一个\(O(nm)\)的算法,考虑继续优化

注意到对于\(x+1\le a_i\)的情况,当\(x++\)时,\(|w|++\),两侧的标记分别左移右移;\(x\ge a_i\)同理

只有当\(x=a_i\)时,类型被改变,标记的移动方式也会发生改变,对每个\(i\)\(a_i\)处进行转换即可

同时,由于需要时刻满足\(w<0\),则每个\(i\)对答案有贡献的合法\(x\)区间为\([2a_i-b_i+1,b_i)\),分别在对应位置插入或删除,还需要考虑插入点与\(a_i\)的关系,记录一下当前属于哪个类别

还需要注意\(b_i-|w|+1,\ b_i+|w|+1\)的取值范围,在二阶差分时考虑更大的区间\((-n,2n]\)

#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 double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline 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 ar[50010],*h1=ar+3500,*h2=ar+13500,*h3=ar+23500,*h4=ar+33500;
bool tag[MAXN];
ll p[20010],bas,ans,*d=p+3500,*sum=p+13500;
vi v1[3010],v2[3010],v3[3010];
struct seg{int l,r,w;}g[MAXN];
void ins(int i,int p)
{
    int w;
    if(!tag[i]) 
    {
        w=g[i].r+p-2*g[i].l;
        h1[g[i].r-w+1]-=g[i].w;
        d[g[i].r+1]+=g[i].w<<1;
        h2[g[i].r+w+1]-=g[i].w;
    }
    else 
    {
        w=g[i].r-p;
        h3[g[i].r-w+1]-=g[i].w;
        d[g[i].r+1]+=g[i].w<<1;
        h4[g[i].r+w+1]-=g[i].w;
    }
}
void chg(int i)
{
    int w=g[i].r-g[i].l;
    tag[i]=1;
    h1[g[i].r-w+1]+=g[i].w;
    h3[g[i].r-w+1]-=g[i].w;
    h2[g[i].r+w+1]+=g[i].w;
    h4[g[i].r+w+1]-=g[i].w;
}
void del(int i)
{
    if(!tag[i])
    {
        h1[g[i].r+1]+=g[i].w;
        d[g[i].r+1]-=g[i].w<<1;
        h2[g[i].r+1]+=g[i].w;
    }
    else 
    {
        h3[g[i].r+1]+=g[i].w;
        d[g[i].r+1]-=g[i].w<<1;
        h4[g[i].r+1]+=g[i].w;
    }
}
int main()
{
    n=read(),m=read();
    rep(i,1,m) 
    {
        g[i].l=read(),g[i].r=read(),g[i].w=read();
        if(g[i].l==g[i].r) continue;
        if(g[i].l>g[i].r) swap(g[i].l,g[i].r);
        bas+=1LL*(g[i].r-g[i].l)*g[i].w;
        if(2*g[i].l-g[i].r+1<1) ins(i,1);
        else v1[2*g[i].l-g[i].r+1].push_back(i);
        if(2*g[i].l-g[i].r+1<g[i].l) v2[g[i].l].push_back(i);
        else tag[i]=1;
        v3[g[i].r].push_back(i);
    }
    rep(x,1,n)
    {
        for(auto i:v1[x]) ins(i,x);
        for(auto i:v3[x]) del(i);
        //rep(i,-n+1,n) cout<<d[i]+h1[i]+h2[i]+h3[i]+h4[i]<<" ";puts("");
        rep(i,-n+1,n) sum[i]=d[i]+h1[i]+h2[i]+h3[i]+h4[i]+sum[i-1];
        rep(i,-n+1,n) sum[i]+=sum[i-1];
        rep(i,1,n) ans=min(ans,sum[i]);
        for(auto i:v2[x]) chg(i);
        rep(i,-n+1,2*n) h1[i]=h1[i+1],h4[i]=h4[i+1];
        dwn(i,2*n,-n+1) h2[i]=h2[i-1],h3[i]=h3[i-1];
    }
    printf("%lld\n",bas+ans);
}

K(结论/瞎搞)

因为本金无限大,每次花两倍的钱去赌,因为概率最小为\(0.01\)且随机,5000次里肯定会赢一次

import sys
y=eval(input().split()[0])
while 1:
    print(y)
    sys.stdout.flush()
    x=eval(input())
    y*=2
    if x==2:
        break

M(签到)

签到题

#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;
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 main()
{
    int n=read(),k=read();
    printf("%d\n",(n-1+k-2)/(k-1));
}
posted @ 2022-09-15 10:28  jack_yyc  阅读(302)  评论(0编辑  收藏  举报