zoukankan      html  css  js  c++  java
  • 2020 Jiangsu Collegiate Programming Contest题解

    A题

    线段树+欧拉降幂

    题目要求的状态只有30种,所以对于每次操作,我们可以枚举所有的情况,计算他的转移方向,我们用lazy标记表示这个数操作完后的状态,打个懒标记

    然后对于询问的时候,只要询问每个数的个数即可。对于快速幂的情况,普通快速幂因为太慢,所以考虑使用欧拉降幂来加速

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e5+10;
    const int mod=1e9+7;
    struct node{
        int l,r;
        int sum[33];
        int lazy[33];
    }tr[N<<2];
    int n,p;
    int cnt[33],num[33];
    int a[N];
    int phi;
    int eular(int n){
        int ans = n;
        for(int i=2;i*i<=n;++i){
            if(n%i == 0){
                ans = ans/i * (i-1);
                while(n % i == 0){
                    n /= i;
                }
            }
        }
        if(n > 1) ans = ans / n * (n - 1);
        return ans;
    }
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    int qmi(int a,int b){
           ll ans=1;
           if(gcd(a,p) == 1){
              b=b%phi;
           }
           else if(b>=phi){
                b=b%phi+phi;
           }
           while(b>0){
                if(b&1) ans=ans*a%p;
                a=a*a%p;
                b>>=1;
           }
           return ans;
    }
    void pushup(int u){
        for(int i=0;i<p;i++){
            tr[u].sum[i]=tr[u<<1].sum[i]+tr[u<<1|1].sum[i];
        }
    }
    void build(int u,int l,int r){
        if(l==r){
            tr[u]={l,r};
            for(int i=0;i<p;i++){
                tr[u].lazy[i]=i;
            }
            tr[u].sum[a[l]%p]++;
        }
        else{
            tr[u]={l,r};
            for(int i=0;i<p;i++){
                tr[u].lazy[i]=i;
            }
            int mid=l+r>>1;
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
            pushup(u);
        }
    }
    int get(int opt,int i,int l){
        if(opt==1){
            return 1ll*(i+l)%p;
        }
        else if(opt==2){
            return 1ll*i*l%p;
        }
        else{
            return 1ll*(qmi(i,l))%p;
        }
    }
    void pushdown(int u){
        int i;
        for(i=0;i<p;i++){
            num[i]=tr[u<<1].sum[i];
            tr[u<<1].sum[i]=0;
        }
        for(i=0;i<p;i++){
            tr[u<<1].sum[tr[u].lazy[i]]+=num[i];
        }
        for(i=0;i<p;i++){
            num[i]=tr[u<<1|1].sum[i];
            tr[u<<1|1].sum[i]=0;
        }
        for(i=0;i<p;i++){
            tr[u<<1|1].sum[tr[u].lazy[i]]+=num[i];
        }
        for(i=0;i<p;i++){
            tr[u<<1].lazy[i]=tr[u].lazy[tr[u<<1].lazy[i]];
            tr[u<<1|1].lazy[i]=tr[u].lazy[tr[u<<1|1].lazy[i]];
        }
        for(i=0;i<p;i++){
            tr[u].lazy[i]=i;
        }
    }
    void modify(int u,int l,int r,int x,int opt){
        if(tr[u].l>=l&&tr[u].r<=r){
            int i;
            for(i=0;i<p;i++){
                num[i]=tr[u].sum[i];
                tr[u].sum[i]=0;
            }
            for(i=0;i<p;i++){
                int pos=get(opt,i,x);
                tr[u].lazy[i]=get(opt,tr[u].lazy[i],x);
                tr[u].sum[pos]+=num[i];
            }
            return ;
        }
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)
            modify(u<<1,l,r,x,opt);
        if(r>mid)
            modify(u<<1|1,l,r,x,opt);
        pushup(u);
    }
    void query(int u,int l,int r){
        if(tr[u].l>=l&&tr[u].r<=r){
            int i;
            for(i=0;i<p;i++){
                cnt[i]+=tr[u].sum[i];
            }
            return ;
        }
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)
            query(u<<1,l,r);
        if(r>mid)
            query(u<<1|1,l,r);
    }
    int main(){
        ios::sync_with_stdio(false);
        int i;
        cin>>n>>p;
        phi=eular(p);
        for(i=1;i<=n;i++)
            cin>>a[i];
        build(1,1,n);
        int q;
        cin>>q;
        while(q--){
            int opt,l,r,k;
            cin>>opt>>l>>r>>k;
            if(opt<=3){
                modify(1,l,r,k,opt);
            }
            else if(opt==4){
                memset(cnt,0,sizeof cnt);
                int ans=0;
                query(1,l,r);
                for(i=0;i<p;i++){
                    ans=(ans+qmi(i,k)*cnt[i])%p;
                }
                cout<<ans<<endl;
            }
            else{
                memset(cnt,0,sizeof cnt);
                int ans=1;
                query(1,l,r);
                for(i=0;i<p;i++){
                    ans=ans*qmi(i,cnt[i])%p;
                }
                cout<<ans<<endl;
            }
        }
        return 0;
    }
    View Code

    C题

    观察到,对于每个数,都放置在比他小1的数的两边就是一种 合法方案,那么这种方案其实就是二叉树的中序遍历

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=5e6+10;
    const int mod=1e9+7;
    int l[N],r[N],w[N];
    int cnt;
    vector<int> num;
    void dfs(int u,int sum){
        w[u]=sum;
        if(sum==20)
            return ;
        l[u]=u<<1,r[u]=u<<1|1;
        dfs(u<<1,sum+1);
        dfs(u<<1|1,sum+1);
    }
    void get(int u){
        if(l[u])
            get(l[u]);
        num.push_back(w[u]);
        if(r[u])
            get(r[u]);
    }
    int main(){
        ios::sync_with_stdio(false);
        int n;
        cin>>n;
        int i;
        dfs(1,1);
        get(1);
        for(i=1;i<=n;i++)
            cout<<num[i]<<" ";
        cout<<endl;
    }
    View Code

    D题

    线段树+思维

    首先要想到小范围的答案不会影响大范围,因此考虑先对操作离线排序。对于下一步

    我们想到,如果直到这个数在第几组删除,并且是这个组的第几个那么就能知道全部答案

    这步操作,可以通过线段树维护,因为每个数只有变成1或者变成当前位置是质数的时候。

    这样只要维护每一轮删除的数,之后从第0轮往上增即可,因为轮数不会太多,所以复杂度过关

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=1e6+10;
    const int mod=1e9+7;
    struct node{
        int l,r;
        int sum;
    }tr[N<<2];
    struct query{
        int op,n,k,id;
    }s[N];
    int num[N],pos[N];
    vector<int> g[N];
    int st[N],primes[N];
    int ans[N];
    bool cmp(query a,query b){
        return a.n<b.n;
    }
    void build(int u,int l,int r){
        if(l==r){
            tr[u]={l,r};
        }
        else{
            tr[u]={l,r};
            int mid=l+r>>1;
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
        }
    }
    void pushup(int u){
        tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
    }
    void modify(int u,int l,int r,int p,int x){
        if(tr[u].l==tr[u].r){
            tr[u].sum+=x;
            return ;
        }
        int mid=tr[u].l+tr[u].r>>1;
        if(p<=mid)
            modify(u<<1,l,r,p,x);
        else
            modify(u<<1|1,l,r,p,x);
        pushup(u);
    }
    int query(int u,int l,int r,int x){
        if(x==0)
            return 0;
        if(tr[u].l==tr[u].r){
            return tr[u].sum;
        }
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=mid){
            return query(u<<1,l,r,x);
        }
        else{
            return tr[u<<1].sum+query(u<<1|1,l,r,x);
        }
    }
    int get(int u,int l,int r,int x){
        if(tr[u].l==tr[u].r){
            return tr[u].l;
        }
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=tr[u<<1].sum){
            return get(u<<1,l,r,x);
        }
        else{
            return get(u<<1|1,l,r,x-tr[u<<1].sum);
        }
    }
    int cnt;
    void init(int mx){
        int i;
        for(i=2;i<=mx;i++){
            if(!st[i]){
                primes[++cnt]=i;
            }
            for(int j=1;primes[j]*i<=mx;j++){
                st[i*primes[j]]=1;
                if(i%primes[j]==0){
                    break;
                }
            }
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        int i;
        int mx=0;
        for(i=1;i<=t;i++){
            cin>>s[i].op>>s[i].n>>s[i].k;
            s[i].id=i;
            mx=max(mx,s[i].n);
        }
        sort(s+1,s+1+t,cmp);
        int now=1;
        build(1,1,1000);
        init(mx);
        for(i=1;i<=mx;i++){
            if(i==1){
                modify(1,1,1000,1,1);
                num[i]=1;
                pos[i]=1;
                g[1].push_back(1);
            }
            else{
                int turn=0;
                while(1){
                    int tmp=query(1,1,1000,turn);
                    if(i-tmp==1||!st[i-tmp]){
                        break;
                    }
                    turn++;
                }
                num[i]=turn+1;
                modify(1,1,1000,turn+1,1);
                g[turn+1].push_back(i);
                pos[i]=g[turn+1].size();
            }
            while(now<=t&&s[now].n==i){
                if(s[now].op==1){
                    int tmpsum=query(1,1,1000,num[s[now].k]-1);
                    tmpsum+=pos[s[now].k];
                    ans[s[now].id]=tmpsum;
                }
                else{
                    int tmpsum=get(1,1,1000,s[now].k);
                    int res=s[now].k-query(1,1,1000,tmpsum-1);
                    ans[s[now].id]=g[tmpsum][res-1];
                }
                now++;
            }
        }
        for(i=1;i<=t;i++)
            cout<<ans[i]<<endl;
        return 0;
    }
    View Code

    H题

    简单dp题,因为发现数据不会很大,因此直接暴力dp匹配即可,注意判断可能模完后变成0和1的情况

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    typedef pair<string,int> pss;
    const int N=1e5+10;
    const int mod=1e9+7;
    ll f[N];
    map<string,int> m1;
    string s;
    ll f1[N];
    int main(){
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--){
            m1.clear();
            memset(f,0,sizeof f);
            memset(f1,0,sizeof f1);
            int n,m;
            cin>>n>>m;
            for(int i=1;i<=m;i++){
                string a,b;
                cin>>a>>b;
                m1[b]++;
            }
            cin>>s;
            s=" "+s;
            f[0]=1;
            f1[0]=1;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=5&&j<=i;j++){
                    string d=s.substr(i-j+1,j);
                    if(m1[d]){
                        f[i]=(f[i]+f[i-j]*m1[d]%128)%128;
                        f1[i]=(f1[i]+f1[i-j]*m1[d]%mod)%mod;
                    }
                }
            }
            if(f[n]==1&&f1[n]==1){
                cout<<"happymorsecode"<<endl;
            }
            else if(!f[n]&&!f1[n]){
                cout<<"nonono"<<endl;
            }
            else{
                cout<<"puppymousecat "<<f[n]<<endl;
            }
        }
    }
    View Code

    I题

    最短路+思维

    注意到这个图是边权不断在变的正权图,因此依旧满足迪杰斯特拉的贪心法则。

    所以我们依旧跑最短路,这依然是正解,只不过要根据时间加两条不同的边。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    typedef pair<string,int> pss;
    const int N=1e5+10;
    const int mod=1e9+7;
    int sx,sy,ex,ey;
    int n,m;
    ll a[505][505],b[505][505];
    ll c[505][505],d[505][505];
    ll dis[5050][505];
    int st[505][505];
    struct node{
        int x,y;
        ll dis;
        bool operator <(const node &t) const{
            return dis>t.dis;
        }
    };
    void dij(){
        memset(dis,0x3f,sizeof dis);
        dis[sx][sy]=0;
        priority_queue<node> q;
        q.push({sx,sy,0});
        while(q.size()){
            auto t=q.top();
            q.pop();
            if(st[t.x][t.y])
                continue;
            st[t.x][t.y]=1;
            ll lim=t.dis%(a[t.x][t.y]+b[t.x][t.y]);
            int x=t.x,y=t.y;
            if(x>1){
                if(lim<a[x][y]){
                    if(dis[x-1][y]>dis[x][y]+d[x-1][y]){
                        dis[x-1][y]=dis[x][y]+d[x-1][y];
                        q.push({x-1,y,dis[x-1][y]});
                    }
                }
                else{
                    ll tmp=a[x][y]+b[x][y]-lim;
                    if(dis[x-1][y]>dis[x][y]+d[x-1][y]+tmp){
                        dis[x-1][y]=dis[x][y]+d[x-1][y]+tmp;
                        q.push({x-1,y,dis[x-1][y]});
                    }
                }
            }
            if(x<n){
                if(lim<a[x][y]){
                    if(dis[x+1][y]>dis[x][y]+d[x][y]){
                        dis[x+1][y]=dis[x][y]+d[x][y];
                        q.push({x+1,y,dis[x+1][y]});
                    }
                }
                else{
                    ll tmp=a[x][y]+b[x][y]-lim;
                    if(dis[x+1][y]>dis[x][y]+d[x][y]+tmp){
                        dis[x+1][y]=dis[x][y]+d[x][y]+tmp;
                        q.push({x+1,y,dis[x+1][y]});
                    }
                }
            }
            if(y>1){
                if(lim>=a[x][y]){
                    if(dis[x][y-1]>dis[x][y]+c[x][y-1]){
                        dis[x][y-1]=dis[x][y]+c[x][y-1];
                        q.push({x,y-1,dis[x][y-1]});
                    }
                }
                else{
                    ll tmp=a[x][y]-lim;
                    if(dis[x][y-1]>dis[x][y]+c[x][y-1]+tmp){
                        dis[x][y-1]=dis[x][y]+c[x][y-1]+tmp;
                        q.push({x,y-1,dis[x][y-1]});
                    }
                }
            }
            if(y<m){
                if(lim>=a[x][y]){
                    //cout<<"gg"<<endl;
                    if(dis[x][y+1]>dis[x][y]+c[x][y]){
                        //cout<<"hh"<<endl;
                        dis[x][y+1]=dis[x][y]+c[x][y];
                        q.push({x,y+1,dis[x][y+1]});
                    }
                }
                else{
                    ll tmp=a[x][y]-lim;
                    if(dis[x][y+1]>dis[x][y]+c[x][y]+tmp){
                        dis[x][y+1]=dis[x][y]+c[x][y]+tmp;
                        q.push({x,y+1,dis[x][y+1]});
                    }
                }
            }
        }
        cout<<dis[ex][ey]<<endl;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m>>sx>>sy>>ex>>ey;
        int i,j;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                cin>>a[i][j];
            }
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                cin>>b[i][j];
            }
        }
        for(i=1;i<=n;i++){
            for(j=1;j<m;j++)
                cin>>c[i][j];
        }
        for(i=1;i<n;i++){
            for(j=1;j<=m;j++)
                cin>>d[i][j];
        }
        dij();
    }
    View Code

    J题

    队友写的

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define LL long long
    #define ull unsigned long long
    #define PI acos(-1.0)
    #define eps 1e-12
    #define fi first
    #define se second
    #define MEM(a,b) memset((a),(b),sizeof(a))
    #define mod(x) ((x)%MOD)
    #define wz cout<<"-----"<<endl;
    #define pb push_back
    #define mp make_pair
    #define pll pair <LL, LL>
    #define pii pair <int, int>
    #define rep(i,x) for(int i=1;i<=x;i++)
    const int INF_INT = 2147483647;
    const ll INF_LL = 9223372036854775807LL;
    const ull INF_ULL = 18446744073709551615Ull;
    const ll P = 92540646808111039LL;
     
    const ll maxn = 1e5 + 10, MOD = 1e9 + 7;
    const int Move[4][2] = {-1,0,1,0,0,1,0,-1};
    const int Move_[8][2] = {-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
     
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int tx[1000033];
    int y;
    int g(int x){
        if(tx[x])return tx[x];
        else return tx[x]=1+g(y%x);
    }
    int main(){
        int t=read();
        while(t--){
            y=read();
            if(y==2){
                printf("%.10lf
    ",1.0);
                continue;
            }
            ll sum=0;
            tx[1]=1;
            for(int i=1;i<=y/2;i++){
                sum+=g(i);
            }
            sum=2*sum+y/2;
            printf("%.10lf
    ",sum*1.0/(y-1));
            for(int i=1;i<y;i++)tx[i]=0;
        }
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    JDBC
    Android--RelativeLayout
    Android--开发过程中使用到的长度单位
    java--进步学习IO
    java--从控制台读入一些数据
    java--IO
    C语言数据结构-创建链表的四种方法
    标准I/O库函数的缺陷
    Java四种引用包括强引用,软引用,弱引用,虚引用
    算法导论答案(1-11)
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/14635066.html
Copyright © 2011-2022 走看看