Codeforces Round #624 (Div. 3)(题解)
A. Add Odd or Subtract Even
思路:
相同直接为0,如果两数相差为偶数就为2,奇数就为1
#include<iostream> #include<algorithm> using namespace std; int main(){ int kk; scanf("%d",&kk); while(kk--){ int n,m; cin>>n>>m; if(n==m) {printf("0\n");continue;} if(m-n>0){ if((m-n)%2){cout<<1<<endl;continue;} else {cout<<2<<endl;continue;} } if(!((n-m)%2)) { cout<<1<<endl; continue;} else cout<<2<<endl; } }
B. WeirdSort
思路:
记录哪些位置可以交换,然后不断循环遍历数组直到没有交换发生,最后再判断一下是否符合要求即可,最坏时间复杂度为冒泡排序O(N2)
#include<iostream> #include<algorithm> #include<vector> #include<cstring> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=105; int a[maxn],b[maxn],flag[maxn]; int main() { int t; scanf("%d",&t); while(t--){ memset(flag,0,sizeof(flag)); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) scanf("%d",&b[i]),flag[b[i]]=1; int num=1; while(num){ num=0; for(int i=1;i<=n;i++){ if(flag[i]){ if(a[i]>a[i+1]){ num=1; swap(a[i],a[i+1]); } } } } int kk=0; for(int i=1;i<n;i++) if(a[i]>a[i+1]) kk=1; if(kk) cout<<"NO"<<endl; else cout<<"YES"<<endl; } return 0; }
C. Perform the Combo
思路:
根据会按错的位置,我们开个数组mp[i] 记录下犯错位置i的次数,然后一个数组c 来维护前缀和按错的字母的总和 然后每次碰到mp[i] 有值的话,我们去循环26个字母,把答案数组a加上当前维护的前缀的c*mp[i] 也就是当前位置犯错的次数就好了
#include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; ll mp[200005]; int b[200005]; char s[200005]; int main() { int t; cin>>t; while(t--) { ll a[130]={0}; ll c[130]={0}; int n,m;cin>>n>>m; cin>>s+1; for(int i=1;i<=n;i++) mp[i]=0; for(int i=1;i<=m;i++){ cin>>b[i]; mp[b[i]]++; } for(int i=1;i<=n;i++){ a[s[i]]++; c[s[i]]++; if(mp[i]){ for(int j='a';j<='z';j++){ a[j]=a[j]+(mp[i]*c[j]); } } } for(int i='a';i<='z';i++) cout<<a[i]<<" "; puts(""); } return 0; }
D. Three Integers
思路:
枚举i,然后枚举i的倍数j,再枚举j的倍数k,找到最小值即可,注意枚举范围一定要大
#include<iostream> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; int main() { int t,a,b,c; scanf("%d",&t); while(t--){ scanf("%d%d%d",&a,&b,&c); int ans=inf,x=0,y=0,z=0; for(int i=1;i<=20000;i++){ for(int j=i;j<=20000;j+=i){ for(int k=j;k<=20000;k+=j){ int kk=abs(a-i)+abs(b-j)+abs(c-k); if(kk<ans){ ans=kk,x=i,y=j,z=k; } } } } cout<<ans<<endl; cout<<x<<" "<<y<<" "<<z<<" "<<endl; } return 0; }
F. Moving Points(树状数组+离散化)
思路:
如果Posx < Posy &&Vx < Vy 那么两点的距离最小值就会为0,否则都为坐标的差值,那答案就是统计∑dis(i,j) (Posi < Posj && Vi ≤ Vj)
看到位置跟速度的范围很大,首先将二者离散化,然后先按照坐标排序
一个点对答案的贡献就为所有坐标比他小并且速度比他小的点距离差值的和,所以就成了一个偏序问题
开两个树状数组sum[0][x]记录速度小于x的点的个数,sum[1][x]记录速度小于x的点的坐标和 动态加点就好了
#include<iostream> #include<algorithm> #define lowbit(x) (x&(-x)) using namespace std; typedef long long ll; const int maxn=2e5+10; struct node{ int x,v; }a[maxn]; int speed[maxn],n; ll sum[2][maxn]; int cmp(node a,node b){return a.x<b.x;} void add(int x,int val) { while(x<=n){ sum[0][x]++,sum[1][x]+=val; x+=lowbit(x); } } ll query(int x,int k) { ll ans=0; while(x>=1){ ans+=sum[k][x]; x-=lowbit(x); } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].x); for(int i=1;i<=n;i++) scanf("%d",&a[i].v),speed[i]=a[i].v; sort(a+1,a+1+n,cmp); sort(speed+1,speed+1+n); unique(speed+1,speed+1+n); ll ans=0; for(int i=1;i<=n;i++){ int now=lower_bound(speed+1,speed+1+n,a[i].v)-speed; ans+=a[i].x*query(now,0)-query(now,1); add(now,a[i].x); } cout<<ans<<endl; return 0; }