總結:題目很難讀,只能靠樣例理解,也不知道代碼寫得對不對,萬幸數據不太強。
A
給一個多項式的因式分解的形式,比如P=(x-a1)(x-a2)...(x-an),要求出多項式除了x^n之外,其他項的系數。n<=10。
比如x^2,就是選2項共享一個x,其他項貢獻ai乘起來,所以dfs搜一下。
//
// Created by zxc on 2020/9/23.
//
#include <bits/stdc++.h>
using namespace std;
int n;
int r[15];
int res[15];
bool vis[15];
void dfs(int i,int now,int tar){
if(i==n+2){
return;
}
if(now==tar){
int t=1;
for(int j=1;j<=n;j++){
if(!vis[j]){
t=t*r[j];
}
}
res[tar]+=t;
return;
}
vis[i]=true;
dfs(i+1,now+1,tar);
vis[i]=false;
dfs(i+1,now,tar);
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&r[i]);
r[i]=-r[i];
}
for(int i=n-1;i>=0;i--){
dfs(1,0,i);
}
for(int i=n-1;i>=0;i--){
printf("%d%c",res[i],i==0?'\n':' ');
}
return 0;
}
B
給定三個數集,大小是1e4,在三個集合里分別找三個數a,b和c,使得|a-b|+|b-c|+|c-a|最小。
這題一開始沒思路放了,思路一開始不對,一直想着正負正負和大小關系,后來想枚舉枚舉,就想到枚舉中間的數,再一看,發現如果枚舉中間的數,那表達式其實就是左右兩個數的距離的2倍。
所以把三個數集排一下序,然后按bac,cab,abc,cba,acb,bca這六種情況,分別枚舉中間的值,然后lower_bound找到左右兩邊最近的一個,再注意判掉一些邊界情況。題目說如果有多個輸出三元組最大的,可是並沒有定義什么是三元組最大的???猜了一下是和最大,就過了。
代碼是我最喜歡的ctrl c+v
//
// Created by zxc on 2020/9/23.
//
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+50;
vector<int> a,b,c;
int as,bs,cs,x;
int ans_a,ans_b,ans_c;
struct node{
int a,b,c;
bool operator <(const node& rhs)const{
return (a+b+c)<(rhs.a+rhs.b+rhs.c);
}
};
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&as,&bs,&cs);
for(int i=0;i<as;i++){
scanf("%d",&x);
a.push_back(x);
}
for(int i=0;i<bs;i++){
scanf("%d",&x);
b.push_back(x);
}
for(int i=0;i<cs;i++){
scanf("%d",&x);
c.push_back(x);
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
sort(c.begin(),c.end());
int ans=0x3f3f3f3f;
// cab
for(int i=0;i<as;i++){
int mid=a[i];
int cx=lower_bound(c.begin(),c.end(),mid)-c.begin();
if(cx==cs){
cx--;
}else if(c[cx]!=mid){
if(cx==0){
continue;
}
cx--;
}
int cc=c[cx];
int bd=lower_bound(b.begin(),b.end(),mid)-b.begin();
if(bd==bs){
continue;
}
int bb=b[bd];
int tmp=2*(bb-cc);
if(tmp<ans){
ans=tmp;
ans_a=mid;
ans_b=bb;
ans_c=cc;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={mid,bb,cc};
if(now<tp){
ans_a=mid;
ans_b=bb;
ans_c=cc;
}
}
}
// bac
for(int i=0;i<as;i++){
int mid=a[i];
int bx=lower_bound(b.begin(),b.end(),mid)-b.begin();
if(bx==bs){
bx--;
}else if(b[bx]!=mid){
if(bx==0){
continue;
}
bx--;
}
int bb=b[bx];
int cd=lower_bound(c.begin(),c.end(),mid)-c.begin();
if(cd==cs){
continue;
}
int cc=c[cd];
int tmp=2*(cc-bb);
if(tmp<ans){
ans=tmp;
ans_a=mid;
ans_b=bb;
ans_c=cc;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={mid,bb,cc};
if(now<tp){
ans_a=mid;
ans_b=bb;
ans_c=cc;
}
}
}
// abc
for(int i=0;i<bs;i++){
int mid=b[i];
int ax=lower_bound(a.begin(),a.end(),mid)-a.begin();
if(ax==as){
ax--;
}else if(a[ax]!=mid){
if(ax==0){
continue;
}
ax--;
}
int aa=a[ax];
int cd=lower_bound(c.begin(),c.end(),mid)-c.begin();
if(cd==cs){
continue;
}
int cc=c[cd];
int tmp=2*(cc-aa);
if(tmp<ans){
ans=tmp;
ans_a=aa;
ans_b=mid;
ans_c=cc;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={aa,mid,cc};
if(now<tp){
ans_a=aa;
ans_b=mid;
ans_c=cc;
}
}
}
// cba
for(int i=0;i<bs;i++){
int mid=b[i];
int cx=lower_bound(c.begin(),c.end(),mid)-c.begin();
if(cx==cs){
cx--;
}else if(c[cx]!=mid){
if(cx==0){
continue;
}
cx--;
}
int cc=c[cx];
int ad=lower_bound(a.begin(),a.end(),mid)-a.begin();
if(ad==as){
continue;
}
int aa=a[ad];
int tmp=2*(aa-cc);
if(tmp<ans){
ans=tmp;
ans_a=aa;
ans_b=mid;
ans_c=cc;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={aa,mid,cc};
if(now<tp){
ans_a=aa;
ans_b=mid;
ans_c=cc;
}
}
}
// acb
for(int i=0;i<cs;i++){
int mid=c[i];
int ax=lower_bound(a.begin(),a.end(),mid)-a.begin();
if(ax==as){
ax--;
}else if(a[ax]!=mid){
if(ax==0){
continue;
}
ax--;
}
int aa=a[ax];
int bd=lower_bound(b.begin(),b.end(),mid)-b.begin();
if(bd==bs){
continue;
}
int bb=b[bd];
int tmp=2*(bb-aa);
if(tmp<ans){
ans=tmp;
ans_a=aa;
ans_b=bb;
ans_c=mid;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={aa,bb,mid};
if(now<tp){
ans_a=aa;
ans_b=bb;
ans_c=mid;
}
}
}
// bca
for(int i=0;i<cs;i++){
int mid=c[i];
int bx=lower_bound(b.begin(),b.end(),mid)-b.begin();
if(bx==bs){
bx--;
}else if(b[bx]!=mid){
if(bx==0){
continue;
}
bx--;
}
int bb=b[bx];
int ad=lower_bound(a.begin(),a.end(),mid)-a.begin();
if(ad==as){
continue;
}
int aa=a[ad];
int tmp=2*(aa-bb);
if(tmp<ans){
ans=tmp;
ans_a=aa;
ans_b=bb;
ans_c=mid;
}else if(tmp==ans){
node now={ans_a,ans_b,ans_c};
node tp={aa,bb,mid};
if(now<tp){
ans_a=aa;
ans_b=bb;
ans_c=mid;
}
}
}
printf("MinD(%d, %d, %d) = %d\n",ans_a,ans_b,ans_c,ans);
return 0;
}
C
題意也是很難讀。。。n個人,每個人有一個分數,然后每個人有一個合照,合照上都是同校的隊友,然后現在要統計所有學校的總分按從高到低排序,每個學校的id就是最小的那個學生id,分數相同按隊員數量從小到大排序,數量相同按id從小到大排序。
id是4位數,所以不用離散化,就先並查集合並一下,然后暴力枚舉全部出現過的id,更新每個學校隊伍的最小學生id,以及統計數量和總分,然后去重,排序。最后輸出記得要%4d。
//
// Created by zxc on 2020/9/23.
//
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int p[N];
int n,k,id[N],sc[N],x;
vector<int> fr[N];
int find(int x){
return x==p[x]?p[x]:p[x]=find(p[x]);
}
int vis[N];
struct node{
int scid;
int allsco;
int num;
int fir=true;
bool operator<(const node& rhs)const{
if(allsco!=rhs.allsco){
return allsco>rhs.allsco;
}else{
if(num!=rhs.num){
return num<rhs.num;
}else{
return scid<rhs.scid;
}
}
}
bool operator ==(const node& rhs)const{
return (allsco==rhs.allsco && num==rhs.num && scid==rhs.scid && fir==rhs.fir);
}
}ans[N];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<=9999;i++){
p[i]=i;
}
for(int i=1;i<=n;i++){
scanf("%d",&id[i]);
vis[id[i]]=true;
scanf("%d",&k);
for(int j=0;j<k;j++){
scanf("%d",&x);
vis[x]=true;
int fa=find(id[i]);
int fb=find(x);
fr[id[i]].push_back(x);
if(fa!=fb){
p[fa]=fb;
}
}
scanf("%d",&sc[id[i]]);
}
for(int i=0;i<=9999;i++){
if(!vis[i]){
continue;
}
int fa=find(i);
ans[fa].allsco+=sc[i];
ans[fa].num++;
if(ans[fa].fir){
ans[fa].scid=i;
ans[fa].fir=false;
}else{
ans[fa].scid=min(ans[fa].scid,i);
}
}
vector<node> v;
for(int i=0;i<=9999;i++){
if(!vis[i]){
continue;
}
int fa=find(i);
v.push_back(ans[fa]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int siz=v.size();
printf("%d\n",siz);
for(int i=0;i<siz;i++){
printf("%04d %d %d\n",v[i].scid,v[i].num,v[i].allsco);
}
return 0;
}
D
題意不知道在講啥。。。連個中心詞coupon都看不懂,估計是優惠還是啥,反正分析樣例就是有n個商品,n個級別的優惠,買一個商品可以得到一個優惠(顯然是選優惠最高的),同理買同一種的第二個商品就只能選第二檔優惠,如果買超過n個同類商品,就沒有優惠了。有d美元,問怎么買可以買到最多的商品。
這題卡了將近一個小時。。。最后靈光一現想到面經里面看過排序幾個有序大文件里的數字,就堆里只要放每個文件的一個指針,然后拿完一個就把對應文件的指針移到下一個數。
所以同理,維護一個堆,先把買每一種商品用第一檔優惠真正需要花的錢放堆里,然后拿出最小的,把對應的商品使用第二檔優惠的花的錢放進去,以此類推,直到錢不夠了。
//
// Created by zxc on 2020/9/23.
//
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int D=1e6+50;
int n,d;
int a[N],b[N];
bool cmp(int x,int y){
return x>y;
}
struct node{
int i,j,cos;
bool operator <(const node& rhs)const{
return cos>rhs.cos;
}
};
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+n,cmp);
priority_queue<node> q;
for(int i=1;i<=n;i++){
q.push(node{i,1,a[i]-b[1]});
}
int ans=0;
int res=d;
while(!q.empty()){
node t=q.top();
q.pop();
res-=t.cos;
if(res<0){
res+=t.cos;
break;
}
ans++;
if(t.j+1<=n){
q.push(node{t.i,t.j+1,a[t.i]-b[t.j+1]});
}else{
// 考試時沒寫上這個,也過了
q.push(node{t.i,t.j+1,a[t.i]});
}
}
printf("%d %d\n",ans,res);
}