2019牛客多校第七场
A.String
传送:https://ac.nowcoder.com/acm/contest/887/A
题意:给定一个$0,1$字符串,要求用划分最少的部分,使得每一部分的字典序为循环的字典序最小。
数据范围:$1<=T<=300,1<=len<=200$。
分析:暴力拆分为以0开始以1结束的字符串,两两合并,直至不可合并。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=300; 4 string aa[maxn],bb[maxn]; 5 char s[maxn]; 6 int tot,tot2; 7 void init(){ 8 int len=strlen(s+1); 9 string ss=""; 10 int flag=1; tot=0; 11 for (int i=1;i<=len;i++){ 12 if(s[i]=='1') ss+=s[i],flag=0; 13 else if(s[i]=='0'){ 14 if(flag) ss+=s[i]; 15 else{ 16 aa[++tot]=ss; ss=s[i]; flag=1; 17 } 18 } 19 if(i==len) aa[++tot]=ss; 20 } 21 } 22 bool check(){ 23 for (int i=1;i<tot;i++){ 24 string x=aa[i],y=aa[i+1]; 25 if(x+y<=y+x) return true; 26 } 27 return false; 28 } 29 string st[maxn]; 30 void solve(){ 31 int top=1; st[1]=""; 32 for (int i=1;i<=tot;i++){ 33 string a=st[top]; 34 string b=aa[i]; 35 string tmp1=a+b,tmp2=b+a; 36 if(tmp1<=tmp2) st[top]=tmp1; 37 else st[++top]=b; 38 } 39 tot=0; 40 for (int i=1;i<=top;i++) aa[++tot]=st[i]; 41 } 42 int main(){ 43 int t;scanf("%d",&t); 44 while (t--){ 45 scanf("%s",s+1); 46 init(); 47 while (1){ 48 if (check()) solve(); 49 else break; 50 } 51 for (int i=1;i<=tot;i++) 52 if (i==1) cout << aa[i]; 53 else cout << " " << aa[i]; 54 cout << endl; 55 } 56 return 0; 57 }
B.Irreducible Polynomial
传送:https://ac.nowcoder.com/acm/contest/887/B
题意:给定一个多项式,问是否可约。
数据范围:$1<=T<=100,1<=n<=20,-10^9<=a_i<=10^9$。
分析:实数域不可拆分多项式只有两种:一次多项式和二次的($b^2<4ac$)。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll a[100]; 5 int main() 6 { 7 int t;scanf("%d",&t); 8 while (t--) 9 { 10 int n;scanf("%d",&n); 11 for (int i=n;i>=0;i--) scanf("%lld",&a[i]); 12 if(n==0 || n==1) {printf("Yes\n");continue;} 13 if(n>=3) {printf("No\n");continue;} 14 ll dd=a[1]*a[1]-4*a[0]*a[2]; 15 if(dd<0) printf("Yes\n"); 16 else printf("No\n"); 17 } 18 return 0; 19 }
C.Governing sand
传送:https://ac.nowcoder.com/acm/contest/887/C
题意:有$n$种树,每种树有高度$h_i$,砍掉的花费$c_i$,数量$p_i$。要求最高的树的数量必须>=一半,问最小的砍掉其他树的花费为多少。
数据范围:$1<=T<=30,1<=n<=10^5,1<=h_i,p_i<=10^9,1<=c_i<=200$。
分析:从从低到高枚举最高的树,在剩下的树当中砍掉代价最小的。用权值线段树维护。
线段树按照代价从小到大构建,然后查询代价尽可能小的。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #define m(a,b) memset(a,b,sizeof a) 6 #define en '\n' 7 using namespace std; 8 typedef long long ll; 9 const int N=2e5+5; 10 const ll INF=1ll<<61ll; 11 struct node{int id;ll h;}a[N]; 12 int cmp(node x,node y){return x.h<y.h;} 13 ll c[N],num[N],sum[N],sb[N];int r[N]; 14 ll tag[N<<2],tsum[N<<2]; 15 void build(ll l,ll r,ll pos){ 16 tag[pos]=tsum[pos]=0; 17 if(l==r) return; 18 ll mid=(l+r)>>1; 19 build(l,mid,pos<<1); 20 build(mid+1,r,pos<<1|1); 21 } 22 void update(ll dex,ll num,ll l,ll r,ll pos) 23 { 24 if(l==r) { 25 tag[pos]+=num,tsum[pos]+=num*l; 26 return; 27 } 28 ll mid=(l+r)>>1; 29 if(dex<=mid) update(dex,num,l,mid,pos<<1); 30 else update(dex,num,mid+1,r,pos<<1|1); 31 tag[pos]=tag[pos<<1]+tag[pos<<1|1];//左边的数量 32 tsum[pos]=tsum[pos<<1]+tsum[pos<<1|1];//左边的金钱 33 } 34 ll query(ll cnt,ll l,ll r,ll pos)//找到cnt个的最小花费 35 { 36 if(l==r) return l*cnt; 37 ll mid=(l+r)>>1; 38 if(tag[pos<<1]>=cnt) return query(cnt,l,mid,pos<<1);//左边的数量够 39 else return tsum[pos<<1]+query(cnt-tag[pos<<1],mid+1,r,pos<<1|1);//左边的金钱+右边询问 40 } 41 int main(){ 42 int n; 43 while(~scanf("%d",&n)) 44 { 45 ll _A=0,Max=0; 46 for(int i=1;i<=n;++i) 47 scanf("%lld%lld%lld",&a[i].h,&c[i],&num[i]),a[i].id=i,_A+=num[i],Max=max(Max,c[i]); 48 build(1,Max,1); 49 sort(a+1,a+n+1,cmp); a[n+1].h=0; 50 for (int i=n;i>=1;i--) 51 { 52 if (a[i].h==a[i+1].h) r[i]=r[i+1]; 53 else r[i]=i; 54 } 55 ll res=0,res2=0; 56 for(int i=n;i>=1;--i) 57 { 58 sum[i]=res,res+=c[a[i].id]*num[a[i].id]; 59 sb[i]=res2,res2+=num[a[i].id]; 60 } 61 res=INF; 62 for(int i=1;i<=n;++i) 63 { 64 int kk=r[i];ll ttt=0; 65 if (r[i]!=r[i+1]) ttt=num[a[i].id]; 66 else{ 67 int j=i; 68 while (r[j]==r[j+1] && j<=n) ttt+=num[a[j++].id]; 69 if (j<=n) ttt+=num[a[j].id]; 70 } 71 ll cnt=_A-sb[kk]-ttt*2+1; 72 ll tmp=sum[kk]; 73 if(cnt>0&&r[i]!=r[i-1]) { 74 tmp+=query(cnt,1,Max,1); //删除cnt个的最小花费 75 res=min(res,tmp); 76 } 77 if(cnt<=0 && r[i]!=r[i-1])res=min(res,tmp); 78 update(c[a[i].id],num[a[i].id],1,Max,1);//在这个花费处添加num个. 79 } 80 printf("%lld\n",res); 81 } 82 return 0; 83 }
D.Number
传送:https://ac.nowcoder.com/acm/contest/887/D
题意:要求输出一个$n$位的是质数$p$的倍数的树,不存在输出T_T。
数据范围:$1<=n<=10^6,2<=p<=10^6$。
分析:直接构造。输出一个$p$,剩下的输出0。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n,p;scanf("%d%d",&n,&p); 7 int tmp=0,x=p; 8 while (x) {x/=10;tmp++;} 9 if(n<tmp) printf("T_T\n"); 10 else 11 { 12 printf("%d",p); 13 for (int i=1;i<=n-tmp;i++) printf("0"); 14 printf("\n"); 15 } 16 return 0; 17 }
E.Find the median
题解传送:https://www.cnblogs.com/changer-qyz/p/11327322.html
J.A+B problem
传送:https://ac.nowcoder.com/acm/contest/887/J
题意:定义$f(x)$为$x$反转后的数。求解$f(f(a)+f(b))$。
分析:暴力。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 char a[50],b[50]; 5 int ans[50]; 6 int main(){ 7 int t;scanf("%d",&t); 8 while (t--){ 9 scanf("%s%s",a,b); 10 int lena=strlen(a),lenb=strlen(b); 11 ll f=1ll; ll aa=0,bb=0; 12 for (int i=0;i<lena;i++){ 13 aa=aa+f*(a[i]-'0'); 14 f*=10; 15 } 16 f=1ll; 17 for (int i=0;i<lenb;i++){ 18 bb=bb+f*(b[i]-'0'); 19 f*=10; 20 } 21 ll kk=aa+bb; int tot=0; 22 while (kk){ 23 ans[++tot]=kk%10; 24 kk/=10; 25 } 26 int i=1; 27 while (ans[i]==0) i++; 28 for (i;i<=tot;i++) printf("%d",ans[i]); 29 printf("\n"); 30 } 31 return 0; 32 }