速度训练3 题解

题目如下:
http://acm.hdu.edu.cn/showproblem.php?pid=5974
http://poj.org/problem?id=3213
http://poj.org/problem?id=3040
http://poj.org/problem?id=3465
http://poj.org/problem?id=3467
http://poj.org/problem?id=3375

A

求x,y使得x+y=a,lcm(x,y)=b.需要判断不存在的情况.
推公式.设 g c d ( x , y ) = k . 则有 ( x k ) + ( y k ) = a k , x k × y k = b k .
可以看到, k 必然是 a , b 的公约数.
我们求出 g c d ( a , b ) 并枚举每一个 k ,根据上面的两个式子解二元二次方程组,逐个检测求出的 x , y 的正确性即可.
单个测试点的时间复杂度是 O ( a ) .

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
int lcm(int a,int b){return a/__gcd(a,b)*b;}
int a,b;

bool judge(int n){
int s=a/n,t=b/n,dt=s*s-4*t;
if (dt<0) return 0;
int sq=sqrt(dt);
if (sq*sq^dt) return 0;
int y=s+sq>>1,x=s-y;
if (y<0||x<0||lcm(x,y)^t) return 0;
printf("%d %d\n",x*n,y*n);
return 1;
}

int main(){
for (;read(a),read(b);){
  int g=__gcd(a,b),i;
  for (i=1;i*i<=g;++i) if (!(g%i)&&(judge(i)||judge(g/i))) break;
  if (i*i>g) puts("No Solution");
  }
}
/*
x+y=a;
x*y=b*gcd(x,y);
设gcd(x,y)=k;
(x/k)*(y/k)=b/k;
(x/k)+(y/k)=a/k.
*/

B

矩阵乘法的时候有一个格子乘错了,让你找出乘错的格子.
暴力模拟矩阵乘法可过.
如果考虑标算,我们去算乘出的矩阵的每行的和.
如果找出一行和与应得不同,暴力模拟这一行找出乘错的数.

#include<cctype> //Ithea Myse Valgulious
#include<cstdio>
#include<algorithm>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int aoi=1018;
typedef int nico[aoi][aoi];
nico a,b,c;
int sa[aoi],sb[aoi],sc[aoi];
int main(){
int i,j,k,n=read(),p=read(),m=read();
for (i=1;i<=n;++i) for (j=1;j<=p;++j) a[i][j]=read();
for (i=1;i<=p;++i) for (j=1;j<=m;++j) sb[i]+=b[i][j]=read();
for (i=1;i<=n;++i) for (j=1;j<=m;++j) sc[i]+=c[i][j]=read();
for (i=1;i<=n;++i){
  int now=0;
  for (j=1;j<=p;++j) now+=a[i][j]*sb[j];
  if (now^sc[i]){
    for (j=1;j<=m;++j){
      int tmp=0;
      for (k=1;k<=p;++k) tmp+=a[i][k]*b[k][j];
      if (tmp^c[i][j]){
        puts("No");
        printf("%d %d\n%d",i,j,tmp);
        return 0;
        }
      }
    }
  }
puts("Yes");
}
/*

*/

C

略.
贪心.
首先把大于或者等于 c 的钞票按照单个直接加上.
然后按照面值从大到小排序,从大开始每次暴力扫,取到小于等于 c 为止.
接下来从小到大扫,将目前的补到大于等于 c ,由于大的面额肯定比小的面额大,这样贪心显然可行.
最后输出答案.

#include<cstdio> //Ithea Myse Valgulious
#include<cctype>
#include<functional>
#include<bitset>
#include<algorithm>
#include<iostream>
#include<cstring>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
#define mz first //面值
#define sl second //数量
typedef pair<int,int> con;
con c[25];int nd[25];

int main(){
int i,j,n=read(),csw=0,k=read();
for (i=1;i<=n;++i){
  c[i].mz=read(),c[i].sl=read();
  if (c[i].mz>k) csw+=c[i].sl,c[i].sl=0; 
  }
sort(c+1,c+n+1,greater<con>());
for (;;){
  int sum=k;
  memset(nd,0,sizeof nd);
  for (i=1;i<=n;++i){
    if (sum>0&&c[i].sl>0){
      int nf=min(c[i].sl,sum/c[i].mz);
      if (nf>0){
        sum-=nf*c[i].mz;
        nd[i]=nf;
        }
      }
    }
  for (i=n;i;i--){
    if (sum>0&&c[i].sl>0){
      int nf=min(c[i].sl-nd[i],(sum+c[i].first-1)/c[i].mz);
      if (nf>0){
        sum-=nf*c[i].mz;
        nd[i]+=nf;
        }
      }
    }
  if (sum>0) break;
  int llx=2147483647;
  for (i=1;i<=n;++i) if (nd[i]) llx=min(llx,c[i].sl/nd[i]);
  csw+=llx;
  for (i=1;i<=n;++i) if (nd[i]) c[i].sl-=llx*nd[i];
  }write(csw);
}

D

你要屠龙,你有攻击,防御,回血三种方法,龙每回合对你造成ai点伤害,你每次的操作在龙之前.
问你打死龙最少需要的回合数,如果你不能在n回合内干掉龙或者被它干掉,输出造成的最大伤害.

贪心,用大根堆维护龙每次对你造成的伤害,先跟它硬刚,如果死了,取出最大的伤害进行防御或者回复(看哪个比较大选哪个),并进行回溯.
注意最后一轮不要判你有没有死,反正你能不能赢也已经确定了,不如在死前给它最后一击来得爽快.

#include<cstdio> //Ithea Myse Valgulious
#include<cctype>
#include<functional>
#include<bitset>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
priority_queue<int> q;

int main(){
int n=read(),i,x,y,h1,h2,ans=0;
read(x),read(y),read(h1),read(h2);
for (i=1;i<=n;++i){
  int a=read(); //龙每回合造成的伤害. 
  ans+=x,h1-=a,h2-=x; //首先模拟你本回合对黑龙进行攻击,造成x点伤害,龙对你造成a点伤害.
  q.push(a);
  if (h2<=0){ //你和主人公一样强,先手把龙干掉了. 
    puts("Win");
    printf("%d\n",i);
    return 0;
    }
  if (i==n) break; //这句break是代码的灵魂.
  /*这一手非常高妙,当第n轮的时候,你已经清楚自己的处境,你发现你即使攻击boss也没有卵用的时候,就给予对手致命一击.
    这时候你还剩多少血,有没有死已经无关紧要了,你要做的就是攻击,不要让战斗停下来.*/ 
  for (;!q.empty()&&h1<=0;){ //你太刚了没看自己血条 
    h1+=max(q.top(),y); //选取当前龙的攻击中最大的攻击,和自己的回复比一下选择是防御还是回复.
    ans-=x,h2+=x,q.pop();
    }
  }
puts("Lose");
write(ans);  
}

E

给一个矩阵,每个格子有个颜色,支持单点修改,求某个颜色十字的数量.
看起来询问乱七八糟,实际上全是单点,可以暴力.
我们预处理每一个颜色十字的数量,存在数组中, O ( 1 ) 回答每一个询问.
修改的时候暴力改相联系的两个颜色,在该点的 4 个方向扫一扫即可.

#include<cctype> //Ithea Myse Valgulious
#include<cstdio>
#include<algorithm>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int _=110;
int a[_][_],n,m,c,q,col[_],b[_][_];

int judge(int x,int y,int c){
int p=x+c,q=y;
if (p<0||q<0||a[p][q]^a[x][y]) return 0;
p=x,q=y+c;
if (p<0||q<0||a[p][q]^a[x][y]) return 0;
p=x-c,q=y;
if (p<0||q<0||a[p][q]^a[x][y]) return 0;
p=x,q=y-c;
if (p<0||q<0||a[p][q]^a[x][y]) return 0;
return 1;
}

int suan(int x,int y){
int i;
for (i=1;i<=999&&judge(x,y,i);++i);
return i-1;
}

void init(){
int i,j;
for (i=1;i<=n;++i) for (j=1;j<=m;++j){
  b[i][j]=suan(i,j);
  col[a[i][j]]+=b[i][j];
  } 
}

void update(int x,int y,int c){
if (a[x][y]==c) return;
col[a[x][y]]-=b[x][y];
col[a[x][y]=c]+=b[x][y]=suan(x,y);
for (int i=1;i<=n;++i) if (i^x){
  col[a[i][y]]-=b[i][y];
  col[a[i][y]]+=b[i][y]=suan(i,y);
  }
for (int i=1;i<=m;++i) if (i^y){
  col[a[x][i]]-=b[x][i];
  col[a[x][i]]+=b[x][i]=suan(x,i);
  }
}

int main(){
n=read(),m=read(),c=read(),q=read();
for (int i=1;i<=n;++i){
  for (int j=1;j<=m;++j) a[i][j]=read();
  }init();
for (;q--;){
  char op=fuhao();
  int x=read(),y,c;
  switch(op){
    case 'C':
      y=read(),c=read();
      update(x,y,c);
      break;
    case 'Q':
      write(col[x]),pl;
      break;
    } 
  }
}

F

n个插头接m台电脑,每个东西有一个坐标,每个插头只能接一个电脑.
接两个东西的花费是abs(x-y),求最小花费.

m 2000 ,从这里入手考虑 d p .
考虑 d p [ i ] [ j ] i j .
直接 d p 复杂度不对.我们来优化.
我们在插头的 a 数组里对 b 数组里的每一个元素进行二分求出 p o s [ i ] ,然后能够将连接的范围确定在 p o s [ i ] m 1 p o s [ i ] + m + 1 之间.
注意直接 d p 还是会爆空间,用双数组优化.
接下来 d p 方程是dp[p][j]=max(dp[p][j-1],dp[p^1][j-1]+abs(b[i]-a[j])).
注意在 d p 的时候要判断上一个状态能否转移到当前状态.
就是上一个枚举的最右端点是否能够与当前的电脑相接.

#include<cstdio> //Ithea Myse Valgulious
#include<cctype>
#include<functional>
#include<bitset>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define Pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5,aoi=2018,inf=0x3f3f3f3f;
typedef int fuko[yuzu|10],azusa[aoi];
fuko a,dp[2];azusa b,pos;
int main(){
int i,j,p=1,n=read(),m=read();
fill(dp[0],dp[0]+n+1,0);
fill(dp[1],dp[1]+n+1,inf);
for (i=1;i<=n;++i) a[i]=read();
for (i=1;i<=m;++i) b[i]=read();
sort(a+1,a+n+1),sort(b+1,b+m+1);
for (i=1;i<=m;++i) pos[i]=lower_bound(a+1,a+n+1,b[i])-a;
int pl=0,pr=n;
for (i=1;i<=m;++i){
  int l=max(i,pos[i]-m-1),r=min(pos[i]+m+1,n);
  dp[p][l-1]=inf;
  for (j=l;j<=r;++j){
    dp[p][j]=min(dp[p][j-1],dp[p^1][j<=pr+1?j-1:pr]+abs(b[i]-a[j]));
    }pl=l,pr=r,p^=1;
  }
write(dp[!p][pr]);
}

谢谢大家.

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/82668675
今日推荐