https://www.patest.cn/contests/pat-a-practise/1055
N=10^5,询问有10^3个,肯定超。并且每个询问都要按序输出前100个值,排序策略不当(区间内的值全部sort再取前k个)更加超。想办法降复杂度。
方法①(由年龄最多200种的约束):先对N个人按年龄划分,每个年龄的人各自排序。对于每个询问for(100次),每次找前第i个值时都for一遍区间内所有的年龄,找到一个最符合的,取出来放到第i个值,并且指针+1。这样复杂度就减少为:1000*100*200.
#include <bits/stdc++.h>
using namespace std;
struct node{
string a;
int c;
bool operator < (const node &X) const{
if(c!=X.c)
return c>X.c;
return a<X.a; //如果是char* a; 二维char数组是不能正确排序的
}
};
vector<node> v[205];
int main(){
int n,m,a,k,cnt=0;
scanf("%d%d",&n,&m);
string x;
int b,c;
for(int i=0;i<n;++i){
cin>>x>>b>>c;
v[b].push_back({x,c});
}
for(int i=1;i<=200;++i){
sort(v[i].begin(),v[i].end());
}
while(m--){
printf("Case #%d:\n",++cnt);
scanf("%d%d%d",&k,&a,&b);
int id[205]={0};
int num=0;
while(k--){
int maxx=-100000000;
string minn;
int p=-1;
for(int i=a;i<=b;++i){
if(id[i]==v[i].size()) continue;
if(v[i][id[i]].c>maxx||
v[i][id[i]].c==maxx&&i<p||
v[i][id[i]].c==maxx&&i==p&&v[i][id[i]].a<minn){
maxx=v[i][id[i]].c;
minn=v[i][id[i]].a;
p=i;
}
}
if(p!=-1){
cout<<v[p][id[p]].a<<" ";
printf("%d %d\n",p,v[p][id[p]].c);//注意!写成cout就超时
id[p]++;
num++;
}
}
if(num==0)
printf("None\n");
}
return 0;
}
方法②(由每个询问按序输出最多100个值的约束):
因为最多也就取前100个,那么先对N个人总体排序,此时N=100000。再把每种年龄的人里面排100名以后的人都去掉,那么每次询问找前100个人中的第i个的最坏情况(跳过前面所有人找最后一个)也就:200*100,而不再是100000。
#include <bits/stdc++.h>
using namespace std;
struct node{
string a;
int b,c;
bool operator < (const node &X) const{
if(c!=X.c)
return c>X.c;
else if(b!=X.b)
return b<X.b;
return a<X.a; //如果是char* a; 二维char数组是不能正确排序的
}
};
vector<node> v,vv;
int main(){
int n,m,a,k,cnt=0;
scanf("%d%d",&n,&m);
string x;
int b,c;
for(int i=0;i<n;++i){
cin>>x>>b>>c;
v.push_back({x,b,c});
}
sort(v.begin(),v.end());
int id[205]={0};
for(int i=0;i<v.size();++i){
id[v[i].b]++;
if(id[v[i].b]<=100) //把每种年龄的人里面排100名以后的人都去掉
vv.push_back(v[i]);
}
while(m--){
printf("Case #%d:\n",++cnt);
scanf("%d%d%d",&k,&a,&b);
int num=0;
for(int i=0;i<vv.size();++i){
if(vv[i].b<a||vv[i].b>b) continue;
cout<<vv[i].a<<" ";
printf("%d %d\n",vv[i].b,vv[i].c);//注意!写成cout就超时
num++;
if(num>=k) break;
}
if(num==0)
printf("None\n");
}
return 0;
}
https://www.patest.cn/contests/pat-a-practise/1103
#include<bits/stdc++.h>
using namespace std;
int x[205];
int path[1005];
int ans[1005];
int n,g,a,u,maxx;
void dfs(int s,int w){
if(w==g){
if(s==n){
u=1;
int sum=0;
for(int i=0;i<w;++i)
sum+=path[i];
if(sum>=maxx){
maxx=sum;
for(int i=0;i<w;++i)
ans[i]=path[i];
}
}
return ;
}
int f=(w>0?path[w-1]:1);
for(int i=f;i<=20;++i){ //从1开始遍历就会超时(但是不理解为什么同样的逆序遍历会超时)
if(s+x[i]>n) break;
path[w]=i;
dfs(s+x[i],w+1);
}
}
int main(){
cin>>n>>g>>a;
for(int j=1;j<=20;++j){
x[j]=pow(j,a);
if(x[j]>400) break;
}
dfs(0,0);
if(u==0)
cout<<"Impossible"<<endl;
else{
cout<<n<<" = ";
for(int i=g-1;i>0;--i)
cout<<ans[i]<<"^"<<a<<" + ";
cout<<ans[0]<<"^"<<a<<endl;
}
}
https://www.patest.cn/contests/pat-a-practise/1063
用map的超时代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,a,b;
vector<int> v[55];
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&m);
while(m--){
scanf("%d",&a);
v[i].push_back(a);
}
}
scanf("%d",&m);
while(m--){
scanf("%d%d",&a,&b);
a--;b--;
map<int,int> r;
int len=(int)v[a].size();
for(int i=0;i<len;++i){
r[v[a][i]]=1;
}
int tmp=r.size();
len=(int)v[b].size();
int s1=0,s2=0;
for(int i=0;i<len;++i){
if(r[v[b][i]]==1){
r[v[b][i]]=-1;
s1++;
}
else if(r[v[b][i]]==0){
s2++;
r[v[b][i]]=-1;
}
}
s2+=tmp-s1;
s2+=s1;
s1*=100;
printf("%.1f",(double)s1/s2);
cout<<"%"<<endl;
}
}
用set不超时,既有去重功能又有.count功能,这样只需要一个for就可解决:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,a,b;
set<int> v[55];
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&m);
while(m--){
scanf("%d",&a);
v[i].insert(a);
}
}
scanf("%d",&m);
while(m--){
scanf("%d%d",&a,&b);
a--;b--;
int s1=0;
for(set<int>::iterator it=v[a].begin();it!=v[a].end();++it){
if(v[b].count(*it))
s1++;
}
printf("%.1f",(double)s1*100/(v[a].size()+v[b].size()-s1));
cout<<"%"<<endl;
}
}