那些年没有AC的水题...
1 HDU 5492(dp
题目:一个数字矩阵,要求找到一条路径使得经过的数字的方差最小.
思路:稍微把式子变换一下,状态是走到当前格子和为k时最小平方和.
/* * @author: Cwind */ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxsum=1900; const int maxn=40; int T,n,m; int grid[maxn][maxn]; int dp[maxn][maxn][maxsum]; int h[maxn][maxn]; int pos[maxn][maxn][maxsum]; int inf; int cas=0; int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); memset(dp,0x3f,sizeof dp); inf=dp[0][0][0]; cin>>T; while(T--){ cin>>n>>m; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&grid[i][j]); } } dp[0][0][grid[0][0]]=sq(grid[0][0]); pos[0][0][0]=grid[0][0]; h[0][0]=1; int ans=inf; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ for(int k=0;k<h[i][j];k++){ int v=pos[i][j][k]; if(dp[i+1][j][v+grid[i+1][j]]==inf){ pos[i+1][j][h[i+1][j]++]=v+grid[i+1][j]; dp[i+1][j][v+grid[i+1][j]]=dp[i][j][v]+sq(grid[i+1][j]); }else{ dp[i+1][j][v+grid[i+1][j]]= min(dp[i][j][v]+sq(grid[i+1][j]), dp[i+1][j][v+grid[i+1][j]]); } if(dp[i][j+1][v+grid[i][j+1]]==inf){ pos[i][j+1][h[i][j+1]++]=v+grid[i][j+1]; dp[i][j+1][v+grid[i][j+1]]=dp[i][j][v]+sq(grid[i][j+1]); }else{ dp[i][j+1][v+grid[i][j+1]]= min(dp[i][j][v]+sq(grid[i][j+1]), dp[i][j+1][v+grid[i][j+1]]); } if(i==n-1&&j==m-1){ ans=min(ans,dp[i][j][v]*(n+m-1)-v*v); } dp[i][j][v]=inf; } h[i][j]=0; } } for(int i=0;i<=max(n,m);i++){ for(int j=0;j<h[i][m];j++){ int v=pos[i][m][j]; dp[i][m][v]=inf; } h[i][m]=0; for(int j=0;j<h[n][i];j++){ int v=pos[n][i][j]; dp[n][i][v]=inf; } h[n][i]=0; } printf("Case #%d: %d\n",++cas,ans); } return 0; }
2 CF 559C
题目:一个棋盘上有若干个格子不能经过,求从左上角走到右下角的方案数.
思路:dp[i]表示走到第i个不能走的点的走法种数,那么这个答案就等于总的走法减去禁止的走法,禁止的走法可以枚举经过的第一个禁止点的位置得到.
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const ll mod=1e9+7; const int maxv=2e5+600; ll inv[maxv]; ll fac[maxv]; ll qpow(ll a,ll p,ll m){ ll ans=1; while(p){ if(p&1) ans=(ans*a)%m; p>>=1; a=(a*a)%m; } return ans; } void init(){ fac[0]=1; for(ll i=1;i<maxv;i++){ fac[i]=fac[i-1]*i%mod; } inv[0]=1; for(ll i=1;i<maxv;i++){ inv[i]=inv[i-1]*qpow(i,mod-2,mod)%mod; } } ll getC(int n,int r){ return fac[n]*inv[n-r]%mod*inv[r]%mod; } const int maxn=2005; struct Point{ int x,y; bool operator < (const Point &C)const { if(x!=C.x) return x<C.x; else return y<C.y; } }a[maxn]; ll h,w,n; ll dp[maxn]; int main(){ freopen("/home/files/CppFiles/in","r",stdin); init(); cin>>h>>w>>n; for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y); a[i].x=x,a[i].y=y; } a[n+1]=(Point){h,w}; sort(a+1,a+n+1); a[0]=(Point){1,1}; for(int i=1;i<=n+1;i++){ ll tmp=0; dp[i]=getC(a[i].x-a[0].x+a[i].y-a[0].y,a[i].x-a[0].x); for(int j=0;j<i;j++){ if(a[j].y<=a[i].y) tmp=(tmp+dp[j]*getC(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%mod)%mod; } tmp=mod-tmp; dp[i]=(dp[i]+tmp)%mod; } cout<<dp[n+1]<<endl; return 0; }
3 HDU 5469
题目:一棵树的每个节点有一个字母,问是否有一条路径组成了指定的字符串.
思路:直接hash+分治,写了差不多一整天....写到都感觉"啊..分治就这么点东西怎么就是不对呢...",然后看了会动漫调整了一下心态,出了个出错的数据才把这题过掉.....这种时候要出一些看起来不会错但是比较复杂的数据,一定不能偷懒...
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define mem(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const ll mod=1e9+7; const ll H=3457; const int maxn=1e4+3000; int T; int n; char c[maxn],s[maxn]; vector<int> G[maxn]; ll hp[maxn]; bool used[maxn]; int cnt; int ch=0; void count(int v,int f=-1){ cnt++; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f||used[u]) continue; count(u,v); } } int snum[maxn]; int center,mind; void getCenter(int v,int f=-1){ snum[v]=0; int maxs=0; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f||used[u]) continue; getCenter(u,v); snum[v]+=snum[u]+1; maxs=max(maxs,snum[u]+1); } if(max(maxs,cnt-snum[v]-1)<mind){ mind=max(maxs,cnt-snum[v]-1); center=v; } } int ls; ll shash1[maxn],shash2[maxn]; int ff[maxn],aa[maxn]; int getfore(int len){return ((shash2[1]-(ll)shash2[len+1]*hp[len])%mod+mod+mod)%mod;} int getafter(int len){return ((shash1[ls]-(ll)shash1[ls-len]*hp[len])%mod+mod+mod)%mod;} int findfore[maxn],findafter[maxn]; int branch; void calhash(int v,ll hash,int d,int f){ ll val=(hash*H+c[v-1])%mod; if(val==ff[d+1]){ if(!findfore[d+1]) findfore[d+1]=branch; else if(findfore[d+1]!=branch) findfore[d+1]=-1; } if(val==aa[d+1]){ if(!findafter[d+1])findafter[d+1]=branch; else if(findafter[d+1]!=branch)findafter[d+1]=-1; } for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f||used[u]) continue; calhash(u,val,d+1,v); } } bool solve(int v){ used[v]=1; branch=1; ch=0; mem(findfore);mem(findafter); findfore[0]=findafter[0]=-1; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(used[u]) continue; calhash(u,0,0,v); branch++; } for(int i=0;i<ls;i++){ if(c[v-1]==s[i]){ if(!findfore[i]||!findafter[ls-i-1])continue; if(findfore[i]>0&&findafter[ls-i-1]>0&&findfore[i]==findafter[ls-i-1])continue; return 1; } } for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(used[u]) continue; cnt=0; count(u); if(cnt<ls) continue; mind=1e9; getCenter(u); if(solve(center))return 1; } return 0; } int cas=0; void init(){ for(int i=0;i<=n;i++){ G[i].clear(); used[i]=0; } } int main(){ freopen("/home/files/CppFiles/in","r",stdin); hp[0]=1; for(int i=1;i<maxn;i++) hp[i]=hp[i-1]*H%mod; cin>>T; while(T--){ cin>>n; init(); for(int i=0;i<n-1;i++){ int a,b; scanf("%d%d",&a,&b); G[a].pb(b); G[b].pb(a); } scanf("%s%s",c,s); ls=strlen(s); for(int i=1;i<=ls;i++) shash1[i]=(shash1[i-1]*H%mod+s[i-1])%mod; shash2[ls+1]=0; for(int i=ls;i>=1;i--){shash2[i]=(shash2[i+1]*H%mod+s[i-1])%mod;} for(int i=0;i<=ls;i++) ff[i]=getfore(i),aa[i]=getafter(i); cnt=0; mind=1e9; count(1); getCenter(1); if(solve(center))printf("Case #%d: Find\n",++cas); else printf("Case #%d: Impossible\n",++cas); } return 0; }
4 HDU 5468
题目:给出一棵树,求每个节点的子树中和这个节点的值互质的数有多少个.
思路:由于只有1e5的数据,所以可以记录每个素数分解的倍数的个数,然后每个子树处理完之后和之前的值减一下就是当前子树中的值.然后容斥原理搞一搞就好了.
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=1e5+400; int n; int cnt[maxn],val[maxn],ans[maxn]; vector<int> G[maxn],fac[maxn]; int mp[maxn]; void dfs(int v,int f=-1){ int pre[80]; clr(pre); int sz=fac[val[v]].size(); for(int mask=0;mask<(1<<sz);mask++){ int tmp=1; for(int j=0;j<sz;j++) if((1<<j)&mask) tmp*=fac[val[v]][j]; pre[mask]=cnt[tmp]; cnt[tmp]++; } for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,v); } for(int mask=0;mask<(1<<sz);mask++){ int tmp=1,f=-1; for(int j=0;j<sz;j++)if((1<<j)&mask) {tmp*=fac[val[v]][j];f*=-1;} ans[v]-=f*(cnt[tmp]-pre[mask]); } } void init_cal(){ for(int i=2;i<maxn;i++)if(!mp[i]) for(int j=i;j<maxn;j+=i){fac[j].pb(i);mp[j]=1;} } void init(){for(int i=0;i<=n;i++) G[i].clear();clr(cnt);clr(ans);} int cas=0; int main(){ freopen("/home/files/CppFiles/in","r",stdin); init_cal(); while(cin>>n){ init(); for(int i=0;i<n-1;i++){ int a,b; scanf("%d%d",&a,&b); G[a].pb(b); G[b].pb(a); } for(int i=1;i<=n;i++) scanf("%d",&val[i]); dfs(1); printf("Case #%d:",++cas); for(int i=1;i<=n;i++) printf(" %d",ans[i]); puts(""); } return 0; }
5 CF 582B
题目:一个数列复制t份首尾相接,求这个数列的最长递增子序列的长度.
思路:这题的一种做法是求前后n段的结果,中间的值都取相同的(只算一段直觉上也是对的,但是显然n段不可能有任何问题,所以不要作死)..另一种做法是矩阵快速幂..但是矩阵快速幂本质上都是dp,所以从dp的角度来考虑.状态dp[i][j]为以大于等于i的数字开头,(当前串的最后一段)以第j个数字结尾的最长序列长度,然后做快速幂.这个状态很巧妙,考虑到a的取值范围在300以内,可以把值作为状态,但是实际的n值更小,这样的状态表示更有效率(如果状态开到300可能会t).最后,对于这种多段问题,矩阵解法表示的一定是在某种约束条件下,最后一段的状态(这样才能dp),由于对这一点理解不清所以看了挺长时间..
/* * @author: Cwind */ #include <bits/stdc++.h> #define pb push_back #define se second #define fs first #define sq(x) (x)*(x) #define eps (5e-12) #define LB lower_bound #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define bk back() #define PB pop_back #define clr(x) memset((x),0,sizeof (x)); using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxn=105; int val[maxn]; int n,t; int tmp[maxn][maxn]; struct Matirx{ int a[maxn][maxn]; Matirx(){ clr(a); } void multi(const Matirx &C){ clr(tmp); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ tmp[i][j]=-INF; for(int k=0;k<n;k++){ tmp[i][j]=max(tmp[i][j],a[i][k]+C.a[k][j]); } } } for(int i=0;i<n;i++) for(int j=0;j<n;j++) a[i][j]=tmp[i][j]; } }; Matirx qpow(Matirx a,int p){ Matirx ans,tmp; while(p){ if(p&1) ans.multi(a); p>>=1; tmp=a; a.multi(tmp); } return ans; } int mat[maxn][maxn]; int main(){ //freopen("/home/files/CppFiles/in","r",stdin); //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); cin>>n>>t; for(int i=0;i<n;i++){ scanf("%d",&val[i]); } for(int s=0;s<n;s++){ for(int i=0;i<n;i++){ if(val[i]<val[s]){ mat[s][i]=-INF; }else{ mat[s][i]=1; for(int j=0;j<i;j++){ if(val[j]<=val[i]) mat[s][i]=max(mat[s][i],mat[s][j]+1); } } } } Matirx A; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ A.a[i][j]=mat[i][j]; } } Matirx ans=qpow(A,t); int aa=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ aa=max(aa,ans.a[i][j]); } } cout<<aa<<endl; return 0; }
6 CF 584E
题目:交换两个数字的花费为这两个数字的位置差,求把一个排列变成另一个排列的最小花费。
思路:先把排列转换成1~n的排列,要吧这个序列转换成顺序排列。做法是从大到小,把没到位置的最大数往后移,并保证不产生多余的花销(不会把一个较大的数移动到它位置的左边)。通过指针移动操作一个数的复杂度是O(n)。这种移动是必然存在满足条件的操作的,因为位置在x之后的数字有n-x个,并且大于x的数字有n-x个,但是由于n在位置x,所以由容斥可知必然存在要求的数字。
/* * @author: Cwind */ #include <bits/stdc++.h> #define pb push_back #define se second #define fs first #define sq(x) (x)*(x) #define eps (5e-12) #define LB lower_bound #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define bk back() #define PB pop_back #define clr(x) memset((x),0,sizeof (x)); using namespace std; typedef int ll; typedef pair<ll,ll> P; const int maxn=2005; int n; int a[maxn],b[maxn]; vector<P> op; int main(){ // freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n;i++){ int x; scanf("%d",&x); b[x]=i; } for(int i=1;i<=n;i++){ a[i]=b[a[i]]; } ll cost=0; for(int i=n;i>=1;i--){ int pos; for(int j=1;j<=n;j++){ if(a[j]==i){ pos=j; break; } } while(pos<i){ int t=pos+1; while(a[t]>pos) t++; cost+=abs(pos-t); swap(a[pos],a[t]); op.pb(P(pos,t)); pos=t; } } cout<<cost<<endl; cout<<op.size()<<endl; for(int i=0;i<op.size();i++){ printf("%d %d\n",op[i].fs,op[i].se); } return 0; }
7 CF 587B
题目:给出由a串重复若干次形成的数列b,求数列b中的长度小于等于k的不降子序列的数量。
思路:由于限定了相邻两项不在同一个a里,所以这题就很简单了(然而比赛的时候脑残居然写挂了。。。。。),统计的时候由于顺序关系,可以用树状数组求和。当然dp的时候完全可以先把a排序,然后求前缀和。
/* * @author: Cwind */ #include <bits/stdc++.h> #define pb push_back #define se second #define fs first #define sq(x) (x)*(x) #define eps (5e-12) #define LB lower_bound #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define bk back() #define PB pop_back #define clr(x) memset((x),0,sizeof (x)); using namespace std; typedef long long ll; typedef pair<ll,ll> P; const ll mod=1e9+7; const int maxn=1e6+3000; ll n,l,k; int h; int lim; struct BIT{ ll a[maxn]; ll sum(int p){ ll ans=0; while(p>0){ ans=(ans+a[p])%mod; p-=p&-p; } return ans; } void add(int p,ll x){ while(p<lim){ a[p]=(a[p]+x)%mod; p+=p&-p; } } void clear(){ for(int i=0;i<=lim;i++){ a[i]=0; } } }B[2]; int dd[maxn]; int a[maxn]; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>n>>l>>k; for(int i=0;i<n;i++){ scanf("%d",&a[i]); dd[i]=a[i]; } sort(dd,dd+n); h=unique(dd,dd+n)-dd; lim=h+300; ll ans=l%mod; if(l<=n){ cout<<l%mod<<endl; return 0; } for(int i=0;i<n;i++){ a[i]=lower_bound(dd,dd+h,a[i])-dd+1; } bool f=0; for(int i=0;i<n;i++){ B[f].add(a[i],1); } ll xx=min(k,l/n); for(int len=2;len<=xx;len++){ f^=1; B[f].clear(); for(int i=0;i<n;i++){ B[f].add(a[i],B[f^1].sum(a[i])); if(l%n!=0&&i+1==l%n) ans=(ans+B[f].sum(lim))%mod; } ans=(ans+B[f].sum(lim)*(l/n%mod-len+1+3*mod)%mod)%mod; } if(l%n!=0&&k>xx&&xx<=l/n+1){ f^=1; B[f].clear(); for(int i=0;i<l%n;i++){ B[f].add(a[i],B[f^1].sum(a[i])); } ans=(ans+B[f].sum(lim))%mod; } cout<<ans<<endl; return 0; }
8 CF 587C
题目:一棵树的每个节点有若干值,询问某两点之间路径上的最小的a个值。
思路:裸倍增lca。
/* * @author: Cwind */ #include <bits/stdc++.h> #define pb push_back #define se second #define fs first #define sq(x) (x)*(x) #define eps (5e-12) #define LB lower_bound #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define bk back() #define PB pop_back #define clr(x) memset((x),0,sizeof (x)); using namespace std; typedef long long ll; typedef pair<ll,ll> P; void print(vector<int> &a){ for(int i=0;i<a.size();i++){ printf("%d ",a[i]); } puts(""); } const int maxn=1e5+300; int n,m,q; vector<int> G[maxn]; vector<int> ls[maxn][18]; int pa[maxn][18]; int dep[maxn]; void dfs(int v,int f=0,int d=0){ pa[v][0]=f;dep[v]=d; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,v,d+1); } } int mergelim=10; void merge(vector<int> &a,vector<int> &b,vector<int> &c){ int h1=0,h2=0; while(h1<a.size()&&h2<b.size()&&c.size()<mergelim){ if(a[h1]<b[h2]){ if(!c.size()||c.bk!=a[h1]){ c.pb(a[h1]); } h1++; }else{ if(!c.size()||c.bk!=b[h2]){ c.pb(b[h2]); } h2++; } } while(h1<a.size()&&c.size()<mergelim){ if(!c.size()||c.bk!=a[h1]){ c.pb(a[h1]); } h1++; } while(h2<b.size()&&c.size()<mergelim){ if(!c.size()||c.bk!=b[h2]){ c.pb(b[h2]); } h2++; } } void cal(){ dfs(1); for(int k=1;k<18;k++){ for(int i=1;i<=n;i++){ pa[i][k]=pa[pa[i][k-1]][k-1]; merge(ls[i][k-1],ls[pa[i][k-1]][k-1],ls[i][k]); } } } vector<int> ans,tmp; void lca(int x,int y){ ans.clear(); if(dep[x]<dep[y]) swap(x,y); for(int k=0;k<18;k++){ if((dep[x]-dep[y])&(1<<k)){ tmp=ans; ans.clear(); merge(tmp,ls[x][k],ans); x=pa[x][k]; } } if(x==y){ tmp=ans; ans.clear(); merge(tmp,ls[x][0],ans); return; } for(int k=18-1;k>=0;k--){ if(pa[x][k]!=pa[y][k]){ tmp=ans; ans.clear(); merge(tmp,ls[x][k],ans); tmp=ans; ans.clear(); merge(tmp,ls[y][k],ans); x=pa[x][k]; y=pa[y][k]; } } tmp=ans; ans.clear(); merge(tmp,ls[x][1],ans); tmp=ans; ans.clear(); merge(tmp,ls[y][0],ans); } int main(){ //freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>n>>m>>q; for(int i=0;i<n-1;i++){ int x,y; scanf("%d%d",&x,&y); G[x].pb(y); G[y].pb(x); } for(int i=1;i<=m;i++){ int x; scanf("%d",&x); if(ls[x][0].size()<10) ls[x][0].pb(i); } cal(); while(q--){ int x,y,z; scanf("%d%d%d",&x,&y,&z); lca(x,y); printf("%d ",min((int)ans.size(),z)); for(int i=0;i<min((int)ans.size(),z);i++){ printf("%d ",ans[i]); } puts(""); } return 0; }
9 CF 589G
题目:离线查询一个数列的前n项中比x大的数之和。
思路:这个题首先要离线排序,天和人都按时间降序,然后注意到如果满足较大的d,那么较小的d一定满足,然后用两个bit维护和和个数。
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=2e5+300; int n,m; P t[maxn]; pair<P,int> c[maxn]; struct BIT{ ll a[maxn]; ll sum(int p){ ll ans=0; while(p>0){ ans+=a[p]; p-=p&-p; } return ans; } void add(int p,int x){ while(p<maxn){ a[p]+=x; p+=p&-p; } } }A,B; int ans[maxn]; int main(){ //freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>n>>m; for(int i=1;i<=m;i++){ scanf("%d",&t[i].fs); t[i].se=i; } for(int i=1;i<=n;i++){ int d,r; scanf("%d%d",&d,&r); c[i].fs.fs=d;c[i].fs.se=r; c[i].se=i; } sort(t+1,t+m+1,greater<P>()); sort(c+1,c+n+1,greater<pair<P,int> >()); int pt=1; for(int i=1;i<=n;i++){ int d=c[i].fs.fs,R=c[i].fs.se; while(t[pt].fs>=d&&pt<=m){ B.add(t[pt].se,t[pt].fs); A.add(t[pt].se,1); pt++; } int l=0,r=m; while(r-l>1){ int mid=(l+r)/2; if(B.sum(mid)-d*A.sum(mid)>=R){ r=mid; }else{ l=mid; } } if(B.sum(r)-d*A.sum(r)>=R) ans[c[i].se]=r; else ans[c[i].se]=0; } for(int i=1;i<=n;i++){ cout<<ans[i]<<" "; } return 0; }