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; } /*样例区 */ //------------------------------------------------------------