2021 Xinjiang Provincial Collegiate Programming Contest

 

 G. cocktail with snake

题意:给区间宽高:n,m,蛇形走位,问k步之后和原点的曼哈顿距离是多少

分析

int t = k / n

就是走k步后当行数

如果 t 是奇数,说明在往左走

如果 t 是偶数,说明在往右走

k % n 就是当前层往左往右走的步数

讨论一下,算出结果就行了

//-------------------------代码----------------------------
 
#define int ll
const int N = 1e5+10;
int n,m,k;
 
void solve()
{
    cin>>n>>m>>k;
//    n-1步
//    1步
//    n-1步
//    k / n就是层数
//    k % n就是位置
    if((k / n) % 2 == 0) {
        cout<< k / n + k % n <<endl;
    } else {
//        k=n -- n-1
//        k=n+1 -- n-2
//        k=2n-1 -- 0
        
        int t = k % n;
        int m = n - 1 - t;
        cout<< k / n +     m<<endl;    
    }
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}
 
/*样例区
 
 
*/
 
//------------------------------------------------------------

K. chino with c language

分析

题意看懂就会了,就是把前面的重复放到某个位置,放几个。另一个是把之前的赋值到某些位置

//#define int ll
const int N = 1e5+10;
int n,m;
char a[N],b[N],c[N];
void solve()
{
//    cin>>n>>m;
    cin>>n;
    cin>>a+1;
    int p1,p2,l;cin>>p1>>p2>>l;
    int cnt = 0;
    fo(i,1,n) {
        b[i] = a[i];
        c[i] = a[i];
    } 
    int tmp = p1;
    fo(i,p2,n) {
        a[i] = a[p1++];
        cnt ++ ;
        if(cnt >= l) break;
    }
    fo(i,1,n) {
        cout<<a[i];
    }
    cout<<endl;
    cnt = 0;
    fo(i,p2,n) {
        c[i] = b[tmp++];
        cnt ++ ;
        if(cnt >= l) break;
    }
    fo(i,1,n) cout<<c[i];cout<<endl;
}

 F. chino with ball

题意:等质碰撞,给每个小球的初始位置和初始速度,问每个小球 k 秒后的位置在哪里

等质换速,k是1e18,直接模拟很复杂。可以看成蚂蚁走路问题,直接穿过,直接算 k 秒后的位置

同时每个球虽然位置变了,但相对位置还是不会变的,记录每个求的 标号,排序后输出就可以了

#define int ll
const int N = 1e5+10;
int n,m,k,f,pos[N],id[N];
 
struct node {
    int p,id;
    bool operator<(const node & x) const {
        return p < x.p;
    }
}a[N];
 
bool cmp(node a,node b) {
    return a.id < b.id;
}
 
void solve()
{
    cin>>n>>k;
    int p,f;
    fo(i,1,n) {
        cin>>p>>f;
        a[i].id = i;
        a[i].p = p;
        pos[i] = p + k * f;
    } 
    sort(pos+1,pos+1+n); 
    sort(a+1,a+1+n);
    fo(i,1,n) {
        a[i].p = pos[i];
    }
    sort(a+1,a+1+n,cmp);
    fo(i,1,n) {
        if(i == n) cout<<a[i].p;
        else cout<<a[i].p<<' ';
    } 
//    cout<<endl;
}

E. is the order a rabbit ??

题意:每天有早上和晚上,每天只能买一次,能卖很多次,问最多的积蓄

只要后面有比当前数大的就可以买入

只要知道数组后面有没有比它当前大的就可以了

给数组从大到小排序,并将它们的位置插入树状数组,如果后面有比当前数大的,在当前坐标的后面就会有数,否则就没有数

//#define int ll
const int N = 1e5+10;
int n,m;

struct node {
    int val,id;
    bool operator<(const node & t) const {
        return val > t.val;
    }
}p[N*2];
int val[N * 2];
int flag[N * 2];
ll num[N * 2];
int cur = 0;
void add(int a) {
    for(int i = a;i<=cur;i+=lowbit(i)) {
        val[i] ++ ;
    }
}

int sum(int a) {
    int res = 0;for(int i = a;i;i-=lowbit(i)) res += val[i];return res;
}
 
void solve()
{
//    cin>>n>>m;
    cin>>n;
    fo(i,1,n) {
        cin>>p[++cur].val;p[cur].id = cur;
        num[cur] = p[cur].val;
        cin>>p[++cur].val;p[cur].id = cur;
        num[cur] = p[cur].val;
    }
    sort(p+1,p+1+cur);
    for(int i = 1;i<= cur;i++) {//前面是最小的,如果后面有比它小的,flag 就是1 
        if(sum(cur) - sum(p[i].id-1)) flag[p[i].id] = 1;
        add(p[i].id);
    }
//    fo(i,1,cur) {
//        cout<<num[i]<<" "; 
//    } cout<<endl;
//    fo(i,1,cur) {
//        cout<<flag[i]<<' ';
//    } cout<<endl;
    ll ans = 0,tmp = 0;
    for(int i = 1;i<=cur;i+=2) {
        if(!flag[i]) {
            ans += tmp * num[i];tmp = 0;
            if(flag[i+1]) ans -= num[i+1],tmp++;//
            continue;
        }
        if(!flag[i+1]) {
            ans -= num[i];tmp ++ ;
            ans += tmp * num[i+1];
            tmp = 0;
            continue;
        }
        ans -= min(num[i],num[i+1]);
        tmp ++ ;
    }
    cout<<ans<<endl;rt;
}

J. do NOT a=2b

题意:问使数组中没有 aj == 2 * ai ,需要删除多少个数

分析:

用值域线性DP。给所有位置有值的地方 + 1,比如a[i] 就是 i 位置有 a[i] 个值

随着 i 的增大,要删除的数会变多,如果最后一个是 前面的数的二倍,可以删除当前这个数,也可以删除前面的数

设dp[i][0/1] 0表示删除,1表示留着

如果 i 是奇数

如果删除 dp[i][0] = a[i]。如果不删除 dp[i][1] = 0;

如果 i 是偶数

如果删除前面的可以删除,可以不删除 dp[i][0] = min(dp[i/2][1] + dp[i/2][0]) + a[i]。如果不删除 dp[i][1] = dp[i/2][0] 前一个数就删了)

 
#define int ll
const int N = 1e6+10;
int n,m;
int a[N],dp[N][2];
int ans;
 
void solve()
{
//    cin>>n>>m;
    cin>>n;int x;
    while(n -- ) {
        cin>>x;
        a[x] ++ ;
    }
    
    fo(i,1,1000000) {
        if(i % 2 == 0) {//如果是偶数
            dp[i][1] = dp[i/2][0];//如果不删除,前一个数必须删除,且删除数量等于前一个数
            dp[i][0] = min(dp[i/2][0],dp[i/2][1]) + a[i];
            //如果删除这个数字,前一个数可以删可以不删,再加上这个数的数量 
            
        } else {//如果是奇数 
            dp[i][0] = a[i];//删掉 
            dp[i][1] = 0;//不删 
        }
    }
    
    fo(i,1,1000000) {
        if(i * 2 > 1000000) ans += min(dp[i][0],dp[i][1]);
    } 
    cout<<ans<<endl;
}

 D. Line

左右两边分别删除就可以了

//#define int ll
const int N = 2e5+10;
int n,m;
 
int a[N],ans[N];
int result[N];
void solve()
{
//    cin>>n>>m;
    cin>>n;
    string s;
    cin>>s;
    int len = s.size();
    s = " " + s;
    ll res = 0;
    fo(i,1,len) {
        if(s[i] == 'L') {
            res += i-1;
            a[i] = i - 1;
        } else {
            res += n-i;
            a[i] = n - i;
        }
    }
//    db(res);
//    gg
    int k = 0;
    
    fo(i,1,n) {
        if(i % 2 == 1) {
            int idx = i / 2 + 1;
//            db(idx);
            if(s[idx] == 'L') {
                k ++ ;
                res = res - a[idx] + (n - idx);
                cout<<res<<' ';
            }
        } else {
            int idx = n - i / 2 + 1;
//            db(idx);
            if(s[idx] == 'R') {
                k ++ ;
                res = res - a[idx] + (idx - 1);
                cout<<res<<' ';
            }
        }
    }
    k ++ ;
    while(k <= n) {
        cout<<res<<' '; 
        k ++ ;
    } cout<<endl;
}

H. cocktail with pony

狼和羊,羊一直往一遍跑,狼也往一边跑,简单模拟一下就可以过了。。

#define int ll
const int N = 1e5+10;
int n,m;
int a[N],b1[N],b2[N];
ll up(ll x,ll y) {
    if(x % y == 0) return x / y;
    return x / y + 1;
}
ll down(ll x,ll y) {
    if(x % y == 0) return x / y;
    return x / y - 1;
}
 
void solve()
{
    int n,v1,v2,x1,x2;
    cin>>n>>v1>>v2>>x1>>x2;
    if(x1 < x2) {
        x1 = n - x1 + 1;
        x2 = n - x2 + 1;
    }
    int cnt = 1;
    while(1) {
        if(cnt & 1) {
            if(x2 == 1 && x1 == 2) break;
            if(x2 - v2 >= 1) {
                x2 -= v2;
            }  else if((v2 - x2) % 2 == 0) {
                x2 = 2;
            } else {
                x2 = 1;
            }
        } else {
            if(x1 - x2 <= v1) break;
            x1 -= v1;
        }
        cnt ++ ;
    }
    cout<<cnt<<endl;
}

D. cocktail with swap

题意:可以交换 位置相差 k . l <=  k <= r 的数,问生成的最小字典序是多少

分析

1. 如果 l == r。只能改变位置相差正好为 l 的数

2. 如果 l >= n / 2 。只能改变[1,n - l],[l + 1,n] 范围内的数 

3. 如果 l <= n / 2。能改变所有数的位置,直接对整个序列排序就可以了

对于第一第二种情况,直接把要排序的数提取出来排序就可以了。

//-------------------------代码----------------------------

//#define int ll
const int N = 1e5+10;
int n,m,l,r;
char tmp[N];
void solve()
{
//    cin>>n>>m;
    cin>>n>>l>>r;
    string s;cin>>s;
    
    if(l == r) {
        for(int i = 0;i < l;i ++ ) {
            int m = 0,j = i;
            while(j < n) tmp[m ++ ] = s[j],j += l;
            sort(tmp,tmp + m);
            
            m = 0,j = i;
            while(j < n) s[j] = tmp[m ++ ],j += l;
        }
    } else if(l <= n / 2) sort(all(s));
    else {
        int m = 0;
        fo(i,0,n-l-1) tmp[m ++ ] = s[i];
        fo(i,l,n-1) tmp[m ++ ] = s[i];
        sort(tmp,tmp + m);
        
        m = 0;
        for(int i = 0;i < n - l; i ++ ) s[i] = tmp[m ++ ];
        for(int i = l;i < n;i ++ ) s[i] = tmp[m ++ ];
    }
    cout<<s;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-30 22:25  er007  阅读(196)  评论(0编辑  收藏  举报