牛客网暑期ACM多校训练营(第四场)

打得头皮发麻。。。
A
比赛的时候维护了每个phi的取模,卡常卡过了。听说有 O(n+log2n) O ( n + l o g 2 n ) 的牛逼算法,就学习了一下。看了下指数循环节,发现好像数据水了,直接mod都能过。

#include 
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
ll mod[30]={
    1000000007,
    1000000006,
    500000002,
    243900800,
    79872000,
    19660800,
    5242880,
    2097152,
    1048576,
    524288,
    262144,
    131072,
    65536,
    32768,
    16384,
    8192,
    4096,
    2048,
    1024,
    512,
    256,
    128,
    64,
    32,
    16,
    8,
    4,
    2,
    1,
    1
};
inline ll power(ll p,ll mod){
    ll ans=1;
    ll base=2;
    while(p){
        if(p&1){
            ans=ans*base%mod;
        }
        base=base*base%mod;
        p>>=1;
    }
    return ans;
}
ll gmax(ll n,ll p){
    ll ans=1;
    ll base=n;
    while(p){
        if(p&1){
            ans=ans*base;
            ans=min(ans,1ll*inf);
        }
        base=base*base;
        base=min(ans,1ll*inf);
        p>>=1;
    }
    return ans;
}
int T;
char s[100003];
int typo[100003];
ll p[30];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        memset(p,0,sizeof(p));
        int len=strlen(s);
        int tmp=0;
        for(int i=len-1;i>=0;i--){
            typo[i]=tmp;
            if(s[i]=='2')tmp++;
        }
        ll ans=0;
        tmp=0;
        for(int i=0;iif(typo[i]>=28)typo[i]=28;
            if(s[i]=='0'){
                ans=(ans+1)%mod[typo[i]];
                tmp=min(tmp+1,inf);
            }
            else if(s[i]=='1'){
                ans=(ans*2+2)%mod[typo[i]];
                tmp=min(tmp*2+2,inf);
            }
            else {
                ans=(6*power(ans+(tmp>=mod[typo[i]+1])*mod[typo[i]+1],mod[typo[i]])-3+mod[typo[i]])%mod[typo[i]];
                tmp=min(1ll*inf,6ll*gmax(2,tmp)-3);
            }
        }
        printf("%lld\n",ans);
    }
}

B
好像是n^2 dp下。

#include
using namespace std;
const int inf=1e9;
struct seg{
    int l,r,w;
}a[2005];

bool cmp(seg a, seg b){
    if(a.r!=b.r) return a.rreturn a.lint t,n,m;
int dp[2005][2005],tmp[2005][2005];

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0; ifor(int j=0; j<=m; j++){
                dp[i][j]=inf;
                tmp[i][j]=inf;
            }
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
        }
        sort(a,a+n,cmp);
        for(int i=0; iif(a[i].l==1)
                tmp[i][1]=a[i].w;
            for(int j=1; j<=a[i].r; j++)
                dp[i][j]=min(dp[i][j-1],tmp[i][j]);
        }
        for(int i=0; ifor(int k=0; kif(a[i].l==a[k].r+1)
                    tmp[i][a[i].l]=min(tmp[i][a[i].l],max(a[i].w,dp[k][a[k].r]));
                if(a[i].l<=a[k].r)
                    tmp[i][a[k].r+1]=min(tmp[i][a[k].r+1],max(a[i].w+a[k].w,dp[k][a[i].l]));
            }
            for(int j=a[i].l; j<=a[i].r; j++)
                dp[i][j]=min(dp[i][j-1],tmp[i][j]);
        }
        int ans=inf;
        /*
        for(int i=0; i
        for(int i=0; iif(ans==inf)
            printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

C
好像确实是标标准准的数位dp啊,尼玛这种玩意儿能不能不要做法各不相同啊,没有智商的solo选手做个蛋蛋啊。

#include 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll dp[61][121][2][2];
ll dig[61];
ll dfs(int pos,int status,int limit,int flag,int pre)
{
    if(pos < 1)return abs(status);
    if(!limit && dp[pos][status+60][flag][pre]!= -1)
        return  dp[pos][status+60][flag][pre];
    int  end = limit ? dig[pos] : 1;
    ll  ret = 0;
    for(int i = 0;i <= end;i ++)
        if(!flag){
            ret+=dfs(pos-1,status,limit&&(i==end),i,i);
        }
        else {
            if(i^pre){
                ret+=dfs(pos-1,status-1,limit&&(i==end),1,i);
            }
            else ret+=dfs(pos-1,status+1,limit&&(i==end),1,i);
        }
    ret%=mod;
    if(!limit)
        dp[pos][status+60][flag][pre]= ret;

    return  ret;
}
int main(){
    memset(dp,-1,sizeof(dp));
    int T;
    scanf("%d",&T);
    while(T--){
        ll n;
        scanf("%lld",&n);
        int pos=0;
        while(n){
            dig[++pos]=n%2;
            n/=2;
        }
        printf("%lld\n",dfs(pos,0,1,0,0));
    }
}

D
玩了一会发现奇数的都不行,偶数的按照正常人思路随便构造一下就完了。

#include 
using namespace std;
int T,n;
int calc(int x,int y){
    if(x+y==n+1){
        if(x>y)return 1;
        else return 0;
    }
    if(x+y1)return 1;
    return -1;
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        if(n%2)printf("impossible\n");
        else {
            printf("possible\n");
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    printf("%d%c",calc(i,j),j==n?'\n':' ');
                }
            }
        }
    }
}

F
签到,随便预处理一下。

#include 
using namespace std;
char s[2003][2003];
int n,m,T;
bool u[2003];
bool v[2003];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
        memset(u,false,sizeof(u));
        memset(v,false,sizeof(v));
        u[0]=v[0]=true;
        for(int l=1,r=n;lif(!u[l-1])break;
            bool ok=true;
            for(int j=1;j<=m;j++){
                ok&=(s[l][j]==s[r][j]);
            }
            u[l]=ok;
        }
        for(int l=1,r=m;lif(!v[l-1])break;
            bool ok=true;
            for(int i=1;i<=n;i++){
                ok&=(s[i][l]==s[i][r]);
            }
            v[l]=ok;
        }
        int ans=0;
        for(int i=1;i2;i++){
            for(int j=1;j2;j++){
                if(u[i]&&v[j])ans++;
            }
        }
        printf("%d\n",ans);
    }
}

G
签到,搞两个map,二分一下。

#include 
using namespace std;
int n,m,T;
map<int,int>mp;
map<int,int>cnt;
int pre[100003];
int sum[100003];
int tot;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        mp.clear();
        cnt.clear();
        tot=0;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            mp[x]++;
        }
        for(auto it=mp.begin();it!=mp.end();it++){
            int x=it->first;
            int tim=it->second;
            cnt[tim]++;
            pre[++tot]=tim;
        }
        sort(pre+1,pre+1+tot);
        for(int i=1;i<=tot;i++){
            sum[i]=pre[i]+sum[i-1];
        }
        int ans=-1;
        for(auto it=mp.begin();it!=mp.end();it++){
            int x=it->first;
            int tim=it->second;
            int up=cnt[tim]+pre+1+tot-upper_bound(pre+1,pre+1+tot,tim);
            int res=up*(tim-1)+1;
            int pos=lower_bound(pre+1,pre+1+tot,tim)-pre-1;
            res+=sum[pos];
            if(res>=n-m){
                ans=max(ans,x);
            }
        }
        printf("%d\n",ans);
    }
}

J
每个点记录从左边往他连线覆盖的区间长度。然后每个点不断地连当前区间左边第一个,扩大区间直到覆盖了初始位置,这样总的连边数是 O(n) O ( n ) 的。用个堆跑一下拓扑排序就行了。

#include 
using namespace std;
int n,m;
int a[200003];
int l[200003];
int d[200003];
int ans[200003];
int tot;
vector<int>g[200003];
priority_queueint,int>,vectorint,int> >,greaterint,int> > >pq;
inline bool check(int r,int len,int x){
    int dis=r-x;
    if(dis<0)dis+=n;
    return disint main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        m=0;
        tot=0;
        for(int i=0;iscanf("%d",&a[i]);
            if(a[i]!=-1)m++;
            d[i]=0;
            l[i]=1;
            g[i].clear();
        }
        bool ok=true;
        for(int i=0;iif(a[i]==-1){
                continue;
            }
            if(a[i]%n==i){
                continue;
            }
            int st=a[i]%n;
            int j=(i-1+n)%n;
            while(1){
                if(a[j]==-1){
                    ok=false;
                    break;
                }
                g[j].push_back(i);
                d[i]++;
                l[i]+=l[j];
                if(check(i,l[i],st))break;
                j-=l[j];
                if(j<0)j+=n;
            }
            if(!ok)break;
        }
        if(!ok){
            printf("-1\n");
            continue;
        }
        for(int i=0;iif(a[i]!=-1&&d[i]==0){
                pq.push(make_pair(a[i],i));
            }
        }
        while(!pq.empty()){
            pair<int,int>pr=pq.top();
            pq.pop();
            ans[++tot]=pr.first;
            int u=pr.second;
            for(int i=0;iint v=g[u][i];
                d[v]--;
                if(!d[v])pq.push(make_pair(a[v],v));
            }
        }
        if(tot!=m){
            printf("-1\n");
        }
        else {
            if(m==0)printf("\n");
            for(int i=1;i<=m;i++)printf("%d%c",ans[i],i==m?'\n':' ');
        }
    }
}

你可能感兴趣的:(contest)