TZOJ 挑战题库随机训练01

点击题号跳转

A2587    B2151    C4672    D4431   E3231

F3706    G3183    H3692    I2665    J1353

A.Toys回到顶部

题意

贝西生日到了,他想庆祝D([1,10^5])天,第i天需要Ti([1,50])个玩具庆祝,1个玩具Tc([1,60])美元,玩具使用过了会变脏,消毒后可以再次使用

消毒方式1:1个玩具消毒N1([1,D])天,花费C1([1,60])美元

消毒方式2:1个玩具消毒N2([1,D])天,花费C2([1,60])美元

问怎么计划使得花费最少?

PS:庆祝273年,牛逼

题解

分析一下,设最小花费是f(x),x为总共买了多个玩具

显然f(x-1)>=f(x)<=f(x+1),少买或多买1个玩具会使得f变大

存在这样一种情况,买了太少的玩具使得怎样都不能满足计划,可设f(x)=inf

单峰函数存在最小值,可用三分解决,这里三分有一个细节

三分lmid=(l+r)/2,rmid=(lmid+r)/2,当lmid=rmid相等时,r-l<=2,如果移动r=rmid,假设答案恰好在r,那么完蛋

也就是说,我们需要保证r-l>2的时候才继续三分,最后[l,r]区间重新算一遍

那么问题就变成已知买了x个玩具求最小花费

显然可以贪心,我们让N1<N2,C1>C2,如果花费时间长还贵,完全可以让C2=C1

那么先用花费时间长N2,再用花费时间短的N1,还不行用x,再不行无解

该如何实现呢?

开3个双端队列,表示等待被消毒,可以用短时间消毒,可以用长时间消毒,代码1,复杂度O(Σalogn),2s接近tle

我们发现第一种方法贪心,每次放进入a[i]个待消毒,Σa复杂度很高

如何优化呢,设q[i]表示第i天剩下的,假设当前处理第i天,i-N2<=i-N1为两个时间节点

对于花费时间长的,维护一个指针top1,当top1<=i-N2可以用min(q[top1],x-a[i])个

对于花费时间短的,相当于top2=i-N1节点往前到top1可以用,发现区间[top1,i-N1]中可能某个为q[i]=0,如果不管,复杂度退化到n^2logn,

发现区间内的值只会不断减小到0,而且要么减成0,要么减成1个值,然后结束,那么就可以用并查集维护向前跳的节点直到top2<top1

代码2,复杂度O(nlognlogn),0.2s

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5;
 5 int a[N];
 6 int d,n1,n2,c1,c2,tc,sum;
 7 deque<int>ti,ts,tl;
 8 //ti 需要被消毒的数量
 9 //ts 花费时间n1少的 c1元(昂贵)
10 //tl 花费事件n2长的 c2元(便宜)
11 int cal(int buy){
12     int sumc=buy*tc;
13     ti.clear();ts.clear();tl.clear();
14     for(int i=1;i<=d;i++){
15         int bought=0;
16         if(buy>=a[i])bought=a[i],buy-=a[i];
17         else bought=buy,buy=0;
18         while(!ti.empty()&&i-ti.front()>=n1){
19             ts.push_back(ti.front());
20             ti.pop_front();
21         }
22         while(!ts.empty()&&i-ts.front()>=n2){
23             tl.push_back(ts.front());
24             ts.pop_front();
25         }
26         while(bought<a[i]){
27             if(!tl.empty())tl.pop_back(),bought++,sumc+=c2;
28             else if(!ts.empty())ts.pop_back(),bought++,sumc+=c1;
29             else return 1e9;
30         }
31         for(int j=1;j<=a[i];j++)ti.push_back(i);
32     }
33     return sumc;
34 }
35 int main(){
36     while(scanf("%d%d%d%d%d%d",&d,&n1,&n2,&c1,&c2,&tc)!=EOF){
37         if(n1>n2){
38             swap(n1,n2);
39             swap(c1,c2);
40         }
41         //花费时间长而且还贵,那肯定不要了
42         if(c2>c1)c2=c1;
43         sum=0;
44         for(int i=1;i<=d;i++){
45             scanf("%d",&a[i]);
46             sum+=a[i];
47         }
48         int l=a[1],r=sum,lmid,rmid;
49         while(r-l>2){
50             lmid=(l+r)>>1;
51             rmid=(lmid+r)>>1;
52             int lval=cal(lmid),rval=cal(rmid);
53             //printf("l=%d lmid=%d rmid=%d r=%d\n",l,lmid,rmid,r);
54             //printf("lval=%d rval=%d\n",lval,rval);
55             if(rval!=1e9&&lval<rval)r=rmid;
56             else l=lmid;
57         }
58         int ans=1e9;
59         for(int i=l;i<=r;i++)ans=min(ans,cal(i));
60         printf("%d\n",ans);
61     }
62     return 0;
63 }
64 /*
65 4 1 3 49 23 59
66 13
67 37
68 26
69 37
70 */
A代码1,O(Σalogn),2s
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int maxn=100010,inf=~0U>>1;
 6 
 7 int n,N1,N2,C1,C2,Tc;
 8 int a[maxn],asum;
 9 int ans;
10 
11 int q[maxn],top1,top2;
12 int fa[maxn];
13 
14 int Find(int x) {return (fa[x]==x)?x:fa[x]=Find(fa[x]);}
15 
16 int f(int x)
17 {
18     for (int i=1;i<=n;i++) q[i]=a[i],fa[i]=i;
19     top1=1;top2=0;
20     int res=Tc*x;
21     for (int i=1;i<=n;i++)
22     {
23         top2=i-N1;
24         if (x<a[i])
25         {
26             while (top1<=i-N2 && x<a[i])
27             {
28                 int m=min(q[top1],a[i]-x);
29                 x+=m;
30                 q[top1]-=m;
31                 res+=C2*m;
32                 if (x<a[i]) top1++; 
33             }
34             while (top2>=top1 && x<a[i])
35             {
36                 int m=min(q[top2],a[i]-x);
37                 x+=m;
38                 q[top2]-=m;
39                 res+=C1*m;
40                 if (x<a[i]) fa[top2]=Find(top2-1),top2=fa[top2];
41             }
42             if (x<a[i]) return inf;
43         }
44         x-=a[i];
45     }
46     return res;
47 }
48 
49 int main()
50 {
51     scanf("%d%d%d%d%d%d",&n,&N1,&N2,&C1,&C2,&Tc);
52     if (N1>N2) swap(N1,N2),swap(C1,C2);
53     if (C1<C2) C2=C1;
54     for (int i=1;i<=n;i++) scanf("%d",&a[i]),asum+=a[i];
55     int l=0,r=asum;
56     while (r-l>2)
57     {
58         int m1=l+(r-l)/3,m2=l+2*((r-l)/3);
59         int fm1=f(m1),fm2=f(m2);
60         if (fm1!=inf && fm1<=fm2) r=m2;else l=m1;
61     }
62     ans=inf;
63     for (int i=l;i<=r;i++) ans=min(ans,f(i));
64     printf("%d\n",ans);
65     return 0;
66 }
A代码2,O(nlognlogn),0.2s

B.Tanning Salon回到顶部

题意

n([1,20])张床,大写字母序列s,字母成对出现,前一个表示进来,后一个表示离开,保证不存在离开晚于有人用完床离开

题解

unordered_map<int,int> ma维护字母是否在使用床

c[i]=1表示字母i进来,0表示i没进来

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 5     int n;string s;
 6     while(cin>>n,n){
 7         cin>>s;
 8         int away=0;
 9         int c[26]={0};
10         unordered_map<int,int>ma;
11         for(int i=0;s[i];i++){
12             if(ma.count(s[i])){
13                 ma.erase(s[i]);
14             }else{
15                 if(ma.size()==n){
16                     if(c[s[i]-'A']==1)away++;
17                     c[s[i]-'A']=1-c[s[i]-'A'];
18                 }
19                 else ma[s[i]]=1;
20             }
21         }
22         if(away==0)cout<<"All customers tanned successfully.\n";
23         else cout<<away<<" customer(s) walked away.\n";
24     }
25     return 0;
26 }
B

C.数据结构―线性表插入删除回到顶部

题意

给定一个线性表,以及若干的插入和删除操作后,输出最终的结果

题解

list基本操作

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 6     int t,n,x,q,m,k;string s;
 7     cin>>t;
 8     while(t--){
 9         list<int>li;
10         cin>>n;
11         for(int i=1;i<=n;i++){
12             cin>>x;
13             li.push_back(x);
14         }
15         list<int>::iterator it;
16         cin>>q;
17         while(q--){
18             cin>>s>>m;
19             it=li.begin();
20             while(--m)it++;
21             list<int>up;
22             if(s[0]=='i'){
23                 cin>>k;
24                 for(int i=1;i<=k;i++){
25                     cin>>x;
26                     up.push_back(x);
27                 }
28                 li.insert(it,up.begin(),up.end());
29             }else{
30                 cin>>k;
31                 while(k--&&it!=li.end())it=li.erase(it);
32             }   
33         }
34         for(it=li.begin();it!=li.end();++it){
35             if(it!=li.begin())cout<<" ";
36             cout<<*it;
37         }
38         cout<<endl;
39     }
40 }
C

D.离散――真值表是个好办法回到顶部

题意

给不超过20个括号组,字母数([1,10]),组间用^,v连接,组内用^,v,->,<->,输出主析取范式和主合取范式

题解

模拟,先处理括号内的每个取值(离散符号不懂的自行百度),再处理外的

PS:一度怀疑数据,感谢詹老哥

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct node{
 4     char l,s,r;
 5     // s='-'<->   s='>'->    s='^'    s='v'
 6 };
 7 int main(){
 8     int n;
 9     while(cin>>n,n){
10         string s;
11         cin>>s;
12         vector<node>v;
13         vector<char>en;
14         for(int i=0;i<s.size();i++){
15             if(s[i]=='('){
16                 node ne;
17                 if(i+4<s.size()&&s[i+4]==')'){
18                     ne.l=s[i+1];ne.s=s[i+2];ne.r=s[i+3];
19                 }else if(i+5<s.size()&&s[i+5]==')'){
20                     ne.l=s[i+1];ne.s='>';ne.r=s[i+4];
21                 }else if(i+6<s.size()&&s[i+6]==')'){
22                     ne.l=s[i+1];ne.s='-';ne.r=s[i+5];
23                 }
24                 v.push_back(ne);
25             }else if(s[i-1]==')'&&(s[i]=='^'||s[i]=='v')){
26                 en.push_back(s[i]);
27             }
28         }
29         int sta=1<<n,cnt=0;
30         bool vis[1030]={0};
31         for(int i=0;i<sta;i++){
32             int val[15];
33             for(int j=0;j<n;j++){
34                 if((1<<j)&i)val[n-j-1]=1;
35                 else val[n-j-1]=0;
36             }
37             vector<int>real;
38             for(int j=0;j<v.size();j++){
39                 int hasl=val[v[j].l-'A'],hasr=val[v[j].r-'A'];
40                 if(v[j].s=='v'&&(hasl||hasr))real.push_back(1);
41                 else if(v[j].s=='^'&&hasl&&hasr)real.push_back(1);
42                 else if(v[j].s=='-'&&hasl==hasr)real.push_back(1);
43                 else if(v[j].s=='>'&&(!hasl||(hasl&&hasr)))real.push_back(1);
44                 else real.push_back(0);
45             }
46             stack<int>pri;
47             stack<char>po;
48             pri.push(real[0]);
49             for(int j=1;j<real.size();j++){
50                 pri.push(real[j]);
51                 if(en[j-1]=='^'){
52                     int v1=pri.top();pri.pop();
53                     int v2=pri.top();pri.pop();
54                     pri.push(v1&v2);
55                 }else{
56                     po.push(en[j-1]);
57                 }
58             }
59             while(!po.empty()){
60                 int v1=pri.top();pri.pop();
61                 int v2=pri.top();pri.pop();
62                 char en1=po.top();po.pop();
63                 pri.push(v1|v2);
64             }
65             if(pri.top()){
66                 vis[i]=1;cnt++;
67             }
68         }
69         int out;
70         if(cnt==0){
71             cout<<"none\n";
72         }else{
73             out=0;
74             for(int i=0;i<sta;i++){
75                 if(!vis[i])continue;
76                 if(out)cout<<"v";
77                 if(out==0)out=1;
78                 cout<<"m"<<i;
79             }
80             cout<<endl;
81         }
82         if(cnt==sta){
83             cout<<"none\n";
84         }else{
85             out=0;
86             for(int i=0;i<sta;i++){
87                 if(vis[i])continue;
88                 if(out)cout<<"^";
89                 if(out==0)out=1;
90                 cout<<"M"<<i;
91             }
92             cout<<endl;
93         }
94     }
95     return 0;
96 }
D

E.表达式求值回到顶部

题意

给一些包含加减号和小括号的表达式,求出该表达式的值。表达式中的数值均为绝对值小于10的整数

题解

模拟,把负数先处理出来,再用栈处理剩下的

PS:代码比较暴躁

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int t;
 7     string s;
 8     cin>>t;
 9     while(t--){
10         cin>>s;
11         vector<int>val;
12         int begin=0;
13         for(int i=0;i<s.size();i++){
14             val.push_back(s[i]);
15             if(s[i]=='-'&&'0'<=s[i+1]&&s[i+1]<='9'){
16                 if('0'<=s[i-1]&&s[i-1]<='9'||s[i-1]==')');
17                 else{
18                     val.pop_back();
19                     val.push_back(-s[i+1]);
20                     i++;
21                 }
22             }
23         }
24         for(int i=0;i<val.size();i++){
25             if(val[i]<0)val[i]=-(-val[i]-'0');
26             else if('0'<=val[i]&&val[i]<='9')val[i]=val[i]-'0';
27         }
28         stack<int>dig,sign;
29         int a,b;
30         for(int i=0;i<val.size();i++){
31             if(abs(val[i])<=9){
32                 dig.push(val[i]);
33             }else if(val[i]=='+'){
34                 if(abs(val[i+1])<=9){
35                     a=dig.top();dig.pop();
36                     //printf("push a=%d + %d val=%d\n",a,val[i+1],a+val[i+1]);
37                     dig.push(a+val[i+1]);
38                     i++;
39                 }else{
40                     //printf("push +\n");
41                     sign.push('+');
42                 }
43             }else if(val[i]=='-'){
44                 if(abs(val[i+1])<=9){
45                     a=dig.top();dig.pop();
46                     //printf("push a=%d - %d val=%d\n",a,val[i+1],a-val[i+1]);
47                     dig.push(a-val[i+1]);
48                     i++;
49                 }else{
50                     //printf("push -\n");
51                     sign.push('-');
52                 }    
53             }else if(val[i]==')'){
54                 //printf(") %c\n",sign.top());
55                 while(sign.top()!='('){
56                     int si=sign.top();sign.pop();
57                     a=dig.top();dig.pop();
58                     b=dig.top();dig.pop();
59                     //printf("?? %d %c %d\n",a,char(si),b);
60                     if(si=='+')dig.push(b+a);
61                     else if(si=='-')dig.push(b-a);
62                 }
63                 sign.pop();
64                 if(!sign.empty()&&sign.top()=='-'){
65                     a=dig.top();dig.pop();
66                     sign.pop();
67                     sign.push('+');
68                     dig.push(-a);
69                 }
70             }else if(val[i]=='('){
71                 //printf("(\n");
72                 sign.push('(');
73             }
74         }
75         while(!sign.empty()){
76             int si=sign.top();sign.pop();
77             a=dig.top();dig.pop();
78             b=dig.top();dig.pop();
79             //printf("%d %c %d\n",a,char(si),b);
80             if(si=='+')dig.push(b+a);
81             else if(si=='-')dig.push(b-a);
82         }
83         cout<<dig.top()<<endl;
84     }
85     return 0;
86 }
E

F.Circle VS Triangle回到顶部

题意

判断圆是否在三角形内部

题解

求圆心到三条边的最短距离,跟r比一下

代码

 1 //#include<bits/stdc++.h>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 
 9 typedef long long LL;
10 
11 const double eps=1e-8;
12 const double pi=acos(-1.0);
13 const int inf=0x7f7f7f7f;
14 
15 inline int dcmp(const double &x){
16     return x>eps?1:(x<-eps?-1:0);
17 }
18 inline double sqr(const double &x){
19     return x*x;
20 }
21 struct Point{
22     double x,y;
23     Point(double x=0,double y=0):x(x),y(y){}
24     Point operator-(const Point &rhs)const{
25         return Point(x-rhs.x,y-rhs.y);
26     }
27     Point operator+(const Point &rhs)const{
28         return Point(x+rhs.x,y+rhs.y);
29     }
30     Point operator/(double scale)const{
31         return Point(x/scale,y/scale);
32     }
33     Point operator*(double scale)const{
34         return Point(x*scale,y*scale);
35     }
36     double operator*(const Point &rhs)const{
37         return x*rhs.x+y*rhs.y;
38     }
39     double operator^(const Point &rhs)const{
40         return x*rhs.y-y*rhs.x;
41     }
42     Point operator-=(const Point &rhs){
43         return *this=*this-rhs;
44     }
45     Point operator+=(const Point &rhs){
46         return *this=*this+rhs;
47     }
48     Point operator/=(double scale){
49         return *this=*this/scale;
50     }
51     Point operator*=(double scale){
52         return *this=*this*scale;
53     }
54     bool operator<(const Point &rhs)const{
55         return dcmp(x-rhs.x)<0||(dcmp(x-rhs.x)==0&&dcmp(y-rhs.y)<0);
56     }
57     bool operator==(const Point &rhs)const{
58         return dcmp(x-rhs.x)==0&&dcmp(y-rhs.y)==0;
59     }
60     double vlen()const{
61         return sqrt(sqr(x)+sqr(y));
62     }
63     Point normal()const{
64         double L=this->vlen();
65         return Point(-y/L,x/L);
66     }
67 };
68 typedef Point Vector;
69 double Dot(Vector A,Vector B){
70     return A*B;
71 }
72 double Cross(Vector A,Vector B){
73     return A^B;
74 }
75 //点到线段的距离
76 double DistanceToSegment(Point P,Point A,Point B){
77     if(A==B)return (P-A).vlen();
78     Vector v1=B-A,v2=P-A,v3=P-B;
79     if(dcmp(Dot(v1,v2))<0)return v2.vlen();
80     else if(dcmp(Dot(v1,v3))>0)return v3.vlen();
81     else return fabs(Cross(v1,v2))/v1.vlen();
82 }
83 int main(){
84     Point p[4];
85     while(scanf("%lf%lf%lf%lf%lf%lf",&p[1].x,&p[1].y,&p[2].x,&p[2].y,&p[3].x,&p[3].y)!=EOF){
86         Point cir;double r;
87         scanf("%lf%lf%lf",&cir.x,&cir.y,&r);
88         if(DistanceToSegment(cir,p[1],p[2])>=r&&DistanceToSegment(cir,p[2],p[3])>=r&&
89             DistanceToSegment(cir,p[1],p[3])>=r)printf("YES\n");
90         else printf("NO\n");
91     }
92     return 0;
93 }
F

G.Hot girl with cool car回到顶部

题意

下图,w代表轨道宽度,r代表转弯半径(轨道内部),θ([0,180])代表曲线角度,求最大转弯半径R

题解

PS:詹老哥牛逼

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const double PI=acos(-1.0);
 4 int main(){
 5     double r,w,s;
 6     while(scanf("%lf%lf%lf",&r,&w,&s)!=EOF){
 7         double c=cos(s*PI/360.0);
 8         printf("%.3f\n",(r+w-c*r)/(1-c));
 9     }
10     return 0;
11 }
G

H.紧急援救回到顶部

题意

n([1,1000])个路口,m([1,10000])条单向边,s个案件,每个案件k辆警车,目的地c,问其中一辆到目的地的最小时间

题解

裸dijstra

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1005;
 4 vector< pair<int,double> >G[N];
 5 double d[N];
 6 queue<int>q;
 7 double dij(int t){
 8     while(!q.empty()){
 9         int u=q.front();q.pop();
10         for(int i=0;i<G[u].size();i++){
11             int v=G[u][i].first;
12             double w=G[u][i].second;
13             if(d[v]>d[u]+w){
14                 d[v]=d[u]+w;
15                 q.push(v);
16             }
17         }
18     }
19     if(d[t]==1e18)return -1;
20     else return d[t];
21 }
22 int main(){
23     int n,m,s;
24     scanf("%d%d%d",&n,&m,&s);
25     for(int i=1;i<=m;i++){
26         int s1,t1;double c1;
27         scanf("%d%d%lf",&s1,&t1,&c1);
28         G[s1].push_back({t1,c1});
29     }
30     int ca=1;
31     while(s--){
32         int c,k,car;
33         scanf("%d%d",&c,&k);
34         for(int i=1;i<=n;i++)d[i]=1e18;
35         while(!q.empty())q.pop();
36         for(int i=1;i<=k;i++){
37             scanf("%d",&car);
38             q.push(car);
39             d[car]=0.0;
40         }
41         printf("Scenario %d:\n",ca++);
42         double ans=dij(c);
43         if(ans==-1)printf("Impossible.\n");
44         else printf("%.2f\n",ans);
45         puts("");
46     }
47     return 0;
48 }
H

I.Fruit回到顶部

题意

n([1,100])个不同水果,购买个数限制[Ai,Bi]([0,100]),问买m([1,100])个水果几种不同方法,数据保证在int内

题解

dp[i][j]代表第i个水果,已经买了j个的方案数

枚举再买j个,已经有k个,dp[i][k+j]+=dp[i-1][k]

复杂度O(n^3)

PS:原数据有爆int,已修正

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 5     int dp[105][105];
 6     int n,m;
 7     while(cin>>n>>m){
 8         memset(dp,0,sizeof dp);
 9         dp[0][0]=1;
10         for(int i=1;i<=n;i++){
11             int a,b;
12             cin>>a>>b;
13             for(int j=a;j<=b;j++)
14                 for(int k=0;k<=m-j;k++)
15                     dp[i][k+j]+=dp[i-1][k];
16         }
17         cout<<dp[n][m]<<'\n';
18     }
19     return 0;
20 }
I

J.Family planning回到顶部

题意

父母最多生M([0,30])个,生了N([0,20])个,若生过男则再生罚款,若超生罚款,罚款1W,2W,4W......

题解

模拟,注意爆int

PS:生20个恐怖如斯

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 int main(){
 5     ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 6     int t;
 7     cin>>t;
 8     while(t--){
 9         int m,n;
10         cin>>m>>n;
11         int f=0;
12         LL sum=0,up=10000;
13         for(int i=1;i<=n;i++){
14             int x;
15             cin>>x;
16             if(f||!m)sum+=up,up+=up;
17             if(m)m--;
18             if(x==1)f=1;
19         }
20         cout<<sum<<" RMB\n";
21     }
22     return 0;
23 }
J

posted on 2020-02-23 21:42  大桃桃  阅读(569)  评论(0编辑  收藏  举报

导航