a 题意:给n个数,每次可以选择2-5个数进行-1操作,当所有数都相等的时候停止,输出可能的最大值,并且输出任意一种方案,当x=0时进行操作,数不会再变小,并且操作次数不能超过10000
分析:最大为最小数,最小为0,n最大100,数最大100,和为1000,每次选择两个数进行操作,也最多5000次,所以只要贪心取最大值,然后再考虑方案
统计所有数的和假设答案的差,如果max*2<sum,那么必然可以找到一种操作方案,如果sum为奇数,就进行一次取三个最大的差,其余的取两个操作就行
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e2+5; 4 struct node{ 5 int id,v; 6 node(){} 7 node(int _id,int _v):id(_id),v(_v){} 8 bool operator < (const node& str)const { 9 return v<str.v; 10 } 11 }; 12 int a[maxn],b[maxn],A[10005][maxn]; 13 int n,_min,cnt; 14 priority_queue<node> q; 15 16 bool test(int t){ 17 int sum=0,_max=-1; 18 for(int i=1;i<=n;i++){ 19 int w=a[i]-t; 20 _max=max(_max,w); 21 sum+=w; 22 } 23 sum-=_max; 24 //cout<<sum<<" "<<_max<<endl; 25 return sum>=_max; 26 } 27 28 bool test1(){ 29 queue<node> qq; 30 int num=q.top().v; 31 bool ok=1; 32 while(!q.empty()){ 33 node tmp=q.top();q.pop(); 34 qq.push(tmp); 35 if(tmp.v!=num){ok=0;break;} 36 } 37 while(!qq.empty()){ 38 q.push(qq.front()); 39 qq.pop(); 40 } 41 return ok; 42 } 43 void adde(node e){ 44 if(e.v==0)q.push(e); 45 else q.push(node(e.id,e.v-1)); 46 } 47 void add1(node e){ 48 if(e.v>0)q.push(node(e.id,e.v-1)); 49 } 50 int main(){ 51 cin>>n;cnt=0;_min=105; 52 for(int i=1;i<=n;i++){ 53 cin>>a[i]; 54 _min=min(_min,a[i]); 55 } 56 int ans=_min; 57 for(;ans>0;ans--)if(test(ans))break; 58 cout<<ans<<endl; 59 if(ans==0){ 60 for(int i=1;i<=n;i++)q.push(node(i,a[i])); 61 while(!test1()){ 62 node q1=q.top();q.pop(); 63 node q2=q.top();q.pop(); 64 adde(q1); 65 adde(q2); 66 A[cnt][q1.id]=A[cnt][q2.id]=1; 67 cnt++; 68 } 69 } 70 else{ 71 int ssum=0; 72 for(int i=1;i<=n;i++){ 73 int w=a[i]-ans;ssum+=w; 74 q.push(node(i,w)); 75 } 76 while(!test1()){ 77 if(ssum&1){ 78 node q1=q.top();q.pop(); 79 node q2=q.top();q.pop(); 80 node q3=q.top();q.pop(); 81 ssum-=3; 82 add1(q1);add1(q2);add1(q3); 83 A[cnt][q1.id]=A[cnt][q2.id]=A[cnt][q3.id]=1; 84 cnt++; 85 } 86 else{ 87 node q1=q.top();q.pop(); 88 node q2=q.top();q.pop(); 89 adde(q1); 90 adde(q2); 91 ssum-=2; 92 A[cnt][q1.id]=A[cnt][q2.id]=1; 93 cnt++; 94 } 95 } 96 } 97 //输出答案 98 cout<<cnt<<endl; 99 for(int i=0;i<cnt;i++){ 100 for(int j=1;j<=n;j++) 101 printf("%d",A[i][j]); 102 puts(""); 103 } 104 return 0; 105 }
b题意:人机问答,给出长度为n的数组,下标从1开始,每次你可以问? a b 表示询问评测机a b下标表示的数,哪个大,回答有= + -三种,要在[3*n/2]-2(表示向上取整)次操作内,询问出最大值和最小值的下标
分析:没做这种人机问答的经验,fflush(stdout),挂了我全场,开始我认为是归并,貌似我归并写挂了,然后分析了下操作次数,开始将数i i+1两两比较,a数组存两个里面的较大值,b存较小值,次数是[n/2],然后一次循环询问最大值和最小值就行了,次数都是[n/2]-1,总次数不会超过要求
#include<bits/stdc++.h> using namespace std; int a[100],b[100]; char op; int test(int c,int d){ printf("? %d %d ",c,d); cin>>op; if(op=='>')return 1; else if(op=='=')return 0; return -1; } int main(){ int t,n; cin>>t; while(t--){ cin>>n; fflush(stdout); int _max,_min,cnt=0; for(int i=1;i<=n;i+=2){ if(i==n){ a[cnt]=b[cnt]=i; } else{ int w=test(i,i+1); if(w==1)a[cnt]=i,b[cnt]=i+1; else if(w==0)a[cnt]=b[cnt]=i; else a[cnt]=i+1,b[cnt]=i; } cnt++; } _max=a[0];_min=b[0]; for(int i=1;i<cnt;i++){ int w=test(_max,a[i]); if(w==-1)_max=a[i]; } for(int i=1;i<cnt;i++){ int w=test(_min,a[i]); if(w==1)_min=a[i]; } printf("! %d %d ",_min,_max); } return 0; }
c题意:n个城市,m条边,每条边长度都是1,然后有k个商店,gi ai,bi分别表示商店所在的城市,货物的数量,价格,然后有q次询问,ai,bi,ci表示ai城市需要bi个商品,总价格不能超过ci,输出所有向他运输产品的城市的最远距离,不存在答案输出-1
分析:先计算所有城市之间的距离,bfs求最短里,时间复杂度O(n^2+n*m),边表示不超过n,对于cf飞快的评测机,5e7小意思,然后二分距离就行了,判断就先把所有商店按照价格排个序,然后判断就ok
d:题意,给了n座桥,相邻的桥紧密连接,然后每座桥给出了长度和最长通过时间,你每分钟走0.5米,还有一种能量棒,每次使用持续r秒,r秒内每分钟走1米,求最少使用能量棒次数分析:能直接走过的桥肯定直接走过,l>t的桥,使用能量棒也无法通过,输出-1,不能直接走过去的桥,就要考虑使用能量棒,每次都是最后的那段时间一直持续在能量棒时间中,这样比在开头用有优势,那就是能量棒可能延伸到下一座或者下几座
g题意:有n辆车,每个车都有一个开始修车的时间,和修车需要的时间,先安排先进入的车,该车的时间段内能修,则安排这个时间,否则找到一个最早的时间,最后输出所有车的修车开始 结束时间
分析:模拟,开个结构体,里面两个元素,表示占用的时间的开始和结束,然后加入新安排的时候判断新加入是否已使用冲突,没冲突加入,冲突的话,开始时间肯定是某个结束时间+1,在占用时间里面价格(0,0),就可以解决1开始的问题
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=205; 4 struct node{ 5 int s,e; 6 node(int a=0,int b=0):s(a),e(b){} 7 bool operator <(const node& str)const{return s<str.s;} 8 }ans[maxn],p[maxn]; 9 int n,x1,x2; 10 11 bool cmp(node a,node b){ 12 if(a.s>b.s)swap(a,b); 13 if(a.e)return false; 14 return true; 15 } 16 17 int main(){ 18 cin>>n; 19 ans[0].s=ans[0].e=0; 20 for(int i=1;i<=n;i++){ 21 scanf("%d%d",&x1,&x2); 22 int a=x1,b=x1+x2-1; 23 bool ok=1; 24 for(int j=1;j<i;j++)if(!cmp(ans[j],node(a,b))){ok=0;break;} 25 if(ok){ 26 p[i].s=ans[i].s=a;p[i].e=ans[i].e=b; 27 } 28 else{ 29 for(int j=0;j<i;j++){ 30 a=ans[j].e+1;b=a+x2-1; 31 ok=1; 32 for(int k=1;k<i;k++)if(!cmp(ans[k],node(a,b))){ok=0;break;} 33 if(ok){ 34 p[i].s=ans[i].s=a;p[i].e=ans[i].e=b;break; 35 } 36 } 37 } 38 sort(ans+1,ans+i+1); 39 } 40 for(int i=1;i<=n;i++) 41 printf("%d %d ",p[i].s,p[i].e); 42 return 0; 43 }
H题意:给n个字符串,然后给出m个选定的字符串,如果这m个字符串长度相同,则这m个字符串组成一个字符串,规则就是,某位置m个字符串都相等则是那个字符,否则就说?,然后?可以代表任意字符,询问是否存在字符串和组合的字符串匹配
分析:模拟,注意都是?的字符串
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+5; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 int n,m; 7 string s[110]; 8 int de[110]; 9 int vis[110]; 10 int main(){ 11 //freopen("in.txt","r",stdin); 12 //ios::sync_with_stdio(false); 13 scanf("%d%d",&n,&m); 14 memset(vis,0,sizeof(vis)); 15 for(int i=1;i<=n;i++){ 16 cin>>s[i]; 17 //cout<<s[i]<<endl; 18 } 19 int flag; 20 for(int i=0;i<m;i++){ 21 scanf("%d",&de[i]); 22 vis[de[i]]=1; 23 24 if(i==0) 25 flag=s[de[i]].size(); 26 else{ 27 if(flag!=s[de[i]].size()){ 28 flag=0; 29 } 30 } 31 //cout<<flag<<endl; 32 } 33 if(flag==0){ 34 printf("No "); 35 } 36 else{ 37 string out=s[de[0]]; 38 int y=out.size(); 39 for(int i=1;i<m;i++){ 40 for(int j=0;j<out.size();j++){ 41 if(out[j]=='?') 42 continue; 43 if(s[de[i]][j]!=out[j]) 44 out[j]='?',y--; 45 } 46 } 47 48 int z1=0; 49 for(int i=1;i<=n;i++){ 50 int z=0; 51 if(vis[i]==1) 52 continue; 53 if(s[i].size()!=out.size()) 54 continue; 55 56 for(int j=0;j<out.size();j++){ 57 if(out[j]=='?') 58 continue; 59 if(s[i][j]==out[j]) 60 { 61 z++; 62 //break; 63 } 64 else 65 break; 66 } 67 if(z==y){ 68 z1=1; 69 break; 70 } 71 } 72 if(z1==1){ 73 printf("No "); 74 } 75 else{ 76 printf("Yes "); 77 cout<<out<<endl; 78 } 79 } 80 return 0; 81 }
I,某学校有n个人,每个人有两个技能值,编程技能和运动技能,现在要选出p个参加编程比赛,s个参加运动会,每个人只能参加一个比赛,使得参加对应比赛的sum(p)+sum(s)最大,并且输出一个组队方案分析:按照p排序,然后dp,dp[i][j],表示前i个选j个s的最大值,ans[i][j]表示选了s选了i,p肯定选钱p个s没选的人,这样就可以做了
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3005; 4 5 struct node{ 6 int id,p,s; 7 bool operator < (const node& str)const{return p>str.p;} 8 }q[maxn]; 9 10 int dp[maxn][maxn]; 11 bool ans[maxn][maxn]; 12 int n,p,s; 13 14 void solve(int i,int j,int w,int ok){ 15 if(dp[i][j]<w){ 16 dp[i][j]=w; 17 ans[i][j]=ok; 18 } 19 } 20 21 int main(){ 22 scanf("%d%d%d",&n,&p,&s); 23 for(int i=0;i<n;i++){ 24 scanf("%d",&q[i].p);q[i].id=i+1; 25 } 26 for(int i=0;i<n;i++)scanf("%d",&q[i].s); 27 sort(q,q+n); 28 29 for(int i=0;i<n;i++){ 30 for(int j=0;j<=min(i,s);j++){ 31 if(i-j<p) 32 solve(i+1,j,dp[i][j]+q[i].p,0); 33 else 34 solve(i+1,j,dp[i][j],0); 35 if(j<s) 36 solve(i+1,j+1,dp[i][j]+q[i].s,1); 37 } 38 } 39 40 //输出答案 41 printf("%d ",dp[n][s]); 42 int i=n,j=s; 43 vector<int> sa,sb; 44 for(;i>0;i--){ 45 if(ans[i][j]){ 46 j--; 47 sb.push_back(q[i-1].id); 48 } 49 else if(i-j<=p) 50 sa.push_back(q[i-1].id); 51 } 52 for(auto& tt:sa)printf("%d ",tt);puts(""); 53 for(auto& tt:sb)printf("%d ",tt);puts(""); 54 return 0; 55 }
J,有n个瓶子,每个瓶子有ai的水,瓶子大小为bi,要将所有的水倒到最少的瓶子里,输出最小的瓶子数和最少的到水量
分析:按照瓶子大小排序,然后贪心选尽量大的瓶子,可以得到要选的瓶子数_min,接下来只要找到一个方案,选取_min个瓶子并且水量最大,答案就说sum-_max,dp就行了,费用就是瓶子大小,价值就是瓶子水量,只要找到费用大于等于sum的最大价值就行了,dp[i][j]表示选i个瓶子,花费j的最大价值,大量状态无法达到,为了节省时间和空间,采用map模拟
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=105; 4 int a[maxn],b[maxn],c[maxn]; 5 int n,sum,_min,cnt,k; 6 map<int,int> v[105]; 7 8 int main(){ 9 cin>>n; 10 for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i]; 11 for(int i=1;i<=n;i++)cin>>b[i],c[i]=b[i]; 12 sort(c+1,c+1+n); 13 for(k=n;cnt<sum;k--)cnt+=c[k]; 14 cnt=n-k; 15 v[0][0]=0; 16 for(int i=1;i<=n;i++) 17 for(int j=cnt-1;j>=0;j--){ 18 for(auto & ttt:v[j]){ 19 int t1=ttt.first+b[i],t2=ttt.second+a[i]; 20 v[j+1][t1]=max(v[j+1][t1],t2); 21 } 22 } 23 int ans=0; 24 for(auto& tt:v[cnt]){ 25 if(tt.first>=sum) 26 ans=max(ans,tt.second); 27 } 28 printf("%d %d ",cnt,sum-ans); 29 30 return 0; 31 }