这场题意都好坑,尤其是A。
C:
题意:选若干水果,至少一个。在sum{b[i]*k}-sum{a[i]}==0时,求最大的sum{a[i]}。
思路:选某个水果对平衡的影响是:b[i]*k-a[i]。dp[balance]表示平衡为balance时,最大的sum{a[i]}。答案在dp[0],平衡有可能负数,整体坐标要右移。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 200100
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
typedef long long ll;
const ll INF = 0x3fffffff;
const int MOD = 7;
const double EPS = 1e-7;
int a[N],b[N];
int dp[2][N];
void update(int &x,int y)
{
if(x==-1) x=y;
x=max(x,y);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",a+i);
for(int i=0;i<n;i++) scanf("%d",b+i),b[i]*=k;
for(int i=0;i<n;i++) b[i]-=a[i];
int pre=0,now=1;
CLR(dp[pre],-1);
dp[pre][10000]=0;
for(int i=0;i<n;i++){
CLR(dp[now],-1);
for(int j=109900;j>=100;j--){
if(dp[pre][j]==-1) continue;
update(dp[now][j],dp[pre][j]);
update(dp[now][j+b[i]],dp[pre][j]+a[i]);
}
swap(pre,now);
}
printf("%d\n",dp[pre][10000]>0?dp[pre][10000]:-1);
return 0;
}
题意:给一张图,每条边有一个范围。你携带一个整数x,如果x落在这条边的范围内,那么你可以通过这条边。你必须从点1带着x走到点n。选择一条路径使得可选的x数量最多,求这个数量。
思路:答案必然是某条边的左边界与某条边的右边界之间的距离。枚举是哪条边的左边界,然后从右边界大的边开始,一直加入集合,直到1和n是连通的。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<ll,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
struct Edge{
int x,y,l,r;
bool operator <(const Edge &t)const{
return r>t.r;
}
}e[N];
int par[N];
void init(int n)
{
for(int i=1;i<=n;i++) par[i]=i;
}
int find(int x){return x==par[x]?x:par[x]=find(par[x]);}
void merge(int x,int y)
{
x=find(x), y=find(y);
if(x==y) return;
par[x]=y;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].l,&e[i].r);
}
sort(e,e+m);
int ans=0;
for(int i=0;i<m;i++){
init(n);
for(int j=0;j<m;j++){
if(e[j].l>e[i].l) continue;
if(e[j].r<e[i].l) break;
merge(e[j].x,e[j].y);
if(find(1)==find(n)){
ans=max(ans,e[j].r-e[i].l+1);
}
}
}
if(ans) cout<<ans<<endl;
else puts("Nice work, Dima!");
return 0;
}
E:
题意:给出音符矩阵,两个音符之间的距离为哈顿距离。最后再给出一串长度为s的音符,求相邻音符中的最大距离。
思路:先选两种音符,再枚举任意两行。选择其中一行最左(右)的点,与另一行最右(左)的点。这样复杂度是O(k*k*n*n),事实上这种复杂度也能过。当然可以优化,观察式子i-j+r[i]-l[j](j<=i),可以维护max{-j-l[j]},另一个式子同理。然后复杂度就将为(k*k*n)
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef long long ll;
typedef pair<ll,int> PI;
const int INF = 0x3fffffff;
const int MOD = 100000007;
const double EPS = 1e-7;
vector<int> d[16][2024];
int a[2024][2024],dis[16][16];
int n,m;
void solve(int x,int y)
{
int L=-INF,R=-INF,ans=0;
for(int i=0;i<n;i++){
if(d[y][i].size()){
L=max(L,-i-d[y][i][0]);
R=max(R,-i+d[y][i][d[y][i].size()-1]);
}
if(L==-INF) continue;
if(d[x][i].size()){
ans=max(ans,i+d[x][i][d[x][i].size()-1]+L);
ans=max(ans,i-d[x][i][0]+R);
}
}
if(x>y) swap(x,y);
dis[x][y]=max(dis[x][y],ans);
}
int main()
{
int k,s,x,y;
scanf("%d%d%d%d",&n,&m,&k,&s);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d",&a[i][j]);
d[a[i][j]][i].push_back(j);
}
}
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
solve(i,j);
int ans=0;
scanf("%d",&x);
for(int i=1;i<s;i++){
scanf("%d",&y);
ans=max(ans,dis[min(x,y)][max(x,y)]);
x=y;
}
printf("%d\n",ans);
return 0;
}