打开博客发现上次咕咕咕了写一半。。想想还是补完,顺便复习下。
A、胖胖的牛牛
好像bfs也行。我这里用的是dfs,后来用了最短路解。
这里主要说最短路。将每个点分成上下左右四个点,用点,其中i、j是点坐标,k为其方向:0为左,1为上,2为右,3为下,(因为当i=n,j=n时,
,所以是
)然后用0点作为超级起点,
作为超级终点,套下最短路就行了。
DFS:
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
template<typename T>void write(T x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
template<typename T> void read(T& x)
{
x = 0; char ch = getchar(); ll f = 1;
while (!isdigit(ch)) { if (ch == '-')f *= -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getchar(); }x *= f;
}
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; };
ll ksm(ll a, ll n) {//看是否要mod
ll ans = 1;
while (n) {
if (n & 1) ans = (ans * a) % mod;
a = a * a % mod;
n >>= 1;
}
return ans % mod;
}
//==============================================================
const int maxn = 1e2 + 10;
int vis[maxn][maxn];
int dir[4][2] = { 1,0,-1,0,0,1,0,-1 };
//上下右左
ll ans = inf;
int xa, xb, ya, yb;
int n;
char mp[maxn][maxn];
void dfs(int x, int y,int pos, ll cnt) {
if(cnt>=ans) return;//剪枝
if(mp[x][y]=='B'){
ans=min(ans,cnt);
return ;
}
rep(i, 0, 3) {
int dx = x + dir[i][0], dy = y + dir[i][1];
if (dx <= 0 || dy <= 0 || dx > n || dy > n || mp[dx][dy] == 'x' || vis[dx][dy]) continue;
vis[dx][dy] = 1;
if (pos == -1 || i == pos) {
dfs(dx, dy, i, cnt);
}
else {
if ((i == 0 && pos == 1) || (i == 1 && pos == 0) || (i == 2 && pos == 3) || (i == 3 && pos == 2)) {
dfs(dx, dy, i, cnt + 2);
}
else {
dfs(dx, dy, i, cnt + 1);
}
}
vis[dx][dy] = 0;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(n);
rep(i, 1, n) {
rep(j, 1, n) {
cin >> mp[i][j];
if (mp[i][j] == 'A') {
xa = i, ya = j;
}
if (mp[i][j] == 'B') {
xb = i, yb = j;
}
}
}
vis[xa][ya] = 1;
dfs(xa, ya, -1, 0);
if (ans >= n * n) {
puts("-1");
}
else {
write(ans);
}
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}最短路:
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=((ans%mod)*(a%mod))%mod;
a=((a%mod)*(a%mod))%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
#define int ll
int n;
const int maxn=105;
char mp[maxn][maxn];
struct Edge{
int to,next,w;
}e[maxn*maxn*5*2];
int head[maxn*maxn*5],cnt;
void add(int x,int y,int w){
e[cnt].w=w;
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
e[cnt].w=w;
e[cnt].to=x;
e[cnt].next=head[y];
head[y]=cnt++;
}
int dis[maxn*maxn*5*2];
struct node{
int u,dis;
node(int uu,int dd){
u=uu;
dis=dd;
}
};
auto cmp=[](const node&a,const node&b){
return a.dis>b.dis;
};
int vis[maxn*maxn*5*2];
priority_queue<node,vector<node>,decltype(cmp)> que(cmp);
int dij(int s,int end){
memset(dis,inf,sizeof(dis));
dis[s]=0;
que.push(node(s,0));
while(!que.empty()){
node a=que.top();
que.pop();
int u=a.u;
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
que.push(node(v,dis[v]));
}
}
}
return dis[end];
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//===========================================================
memset(head,-1,sizeof(head));
read(n);
rep(i,1,n){
rep(j,1,n){
cin>>mp[i][j];
}
}
/*rep(i,1,n){
rep(j,1,n){
cerr<<mp[i][j];
}
cerr<<endl;
}*/
//0 left 1 up 2 right 3 down
rep(i,1,n){
rep(j,1,n){
if(mp[i][j]=='x') continue;
int left=(i-1)*n+j,up=(i-1)*n+j+1*n*n,right=(i-1)*n+j+2*n*n,down=(i-1)*n+j+3*n*n;
add(left,up,1),add(up,right,1),add(right,down,1),add(down,left,1);
add(left,right,0),add(up,down,0);
if(j>1){
int lr=(i-1)*n+j-1+2*n*n;
add(lr,left,0);
}
if(j<n){
int rl=(i-1)*n+j+1+0*n*n;
add(rl,right,0);
}
if(i>1){
int ud=(i-2)*n+j+3*n*n;
add(up,ud,0);
}
if(i<n){
int du=(i+0)*n+j+1*n*n;
add(du,down,0);
}
if(mp[i][j]=='A'){
int ss=0;
add(ss,left,0);
add(ss,right,0);
add(ss,up,0);
add(ss,down,0);
}
if(mp[i][j]=='B'){
int se=4*n*n+1;
add(se,left,0);
add(se,right,0);
add(se,up,0);
add(se,down,0);
}
}
}
int ans=dij(0,4*n*n+1);
if(ans>=n*n){
puts("-1");
}
else{
write(ans);
}
//===========================================================
return 0;
}B.牛牛的零食
这道题很明显是组合数学。他要求的是[a,b]范围内符合条件的数,一般这种都是转化为cal(b)-cal(a-1),因为在1~n的范围内求某个数a的倍数的个数可以用n/a得到。这里还有其他的附加条件:不能被其它数整除,那么,考虑容斥原理:对于一个数n,可以被8整除的有n/8个,之后,不能被其他的数整除,其实应该要减去的是既是8的倍数,又是该数的倍数的,所以是lcm(8,x),按这样去除之后,显然会去多,所以再加回来,例如:
3
7764 6082 462
那就是,这个过程可以用dfs实现(也可以用队列数组或者二进制)。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=((ans%mod)*(a%mod))%mod;
a=((a%mod)*(a%mod))%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
#define int ll
int n,xs[20];
int a,b,ans;
void dfs(int x,int l,int s,int sig){
if(l>n){
ans+=sig*x/s;
return ;
}
dfs(x,l+1,s,sig);
dfs(x,l+1,(s*xs[l])/gcd(s,xs[l]),-sig);
}
int cal(int x){
ans=0;
dfs(x,1,8,1);
return ans;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//===========================================================
read(n);
rep(i,1,n) read(xs[i]);
read(a),read(b);
write(cal(b)-cal(a-1));
//===========================================================
return 0;
}C.牛牛的最美味和最不美味的零食
这道题的正确做法应该是记住树的siz,然后根据左子树siz的大小选择跳左子树还是跳右子树。需要注意的是,在eat的时候,需要先用连个变量存下左子树的siz和右子树的siz,因为eat之后siz会改变,可能导致一次吃了两个糖,当然,也可以用else if,个人习惯。
另一种做法是看大佬的:用树状数组记录前面吃掉的糖果数,每次query的时候,二分查找到idx1-前缀和(idx1)==i和idx2-前缀和(idx2)==j,这个就是现在要找的这个区间的对应原始的断点的位置,之后就像普通查找一样query原始端点就行了,但复杂度会高一些。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=((ans%mod)*(a%mod))%mod;
a=((a%mod)*(a%mod))%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
#define int ll
#define lson (rt<<1)
#define rson (rt<<1|1)
#define pii pair<int,int>
int n,m;
const int maxn=1e6+10;
struct node{
int siz,l,r,mi,ma;
}tree[maxn<<2];
void pushup(int rt){
tree[rt].ma=max(tree[lson].ma,tree[rson].ma);
tree[rt].mi=min(tree[lson].mi,tree[rson].mi);
tree[rt].siz=(tree[lson].siz+tree[rson].siz);
}
void build(int l,int r,int rt){
tree[rt].l=l,tree[rt].r=r;
if(l==r){
read(tree[rt].ma);
tree[rt].mi=tree[rt].ma;
tree[rt].siz=1;
return ;
}
int m=(l+r)>>1;
build(l,m,lson);
build(m+1,r,rson);
pushup(rt);
}
void eat(int tar,int rt){
int l=tree[rt].l,r=tree[rt].r;
if(l==r){
tree[rt].siz=0;
tree[rt].ma=-inf;
tree[rt].mi=inf;
return;
}
int siz1=tree[lson].siz;
if(tar<=siz1) eat(tar,lson);
if(tar>siz1) eat(tar-siz1,rson);
pushup(rt);
}
pii query(int ql,int qr,int rt){
if(ql<=1&&qr>=tree[rt].siz){
return make_pair(tree[rt].mi,tree[rt].ma);
}
int ma=-inf,mi=inf;
if(ql<=tree[lson].siz){
pii t=query(ql,qr,lson);
ma=max(ma,t.second);
mi=min(mi,t.first);
}
if(qr>tree[lson].siz){
pii t=query(ql-tree[lson].siz,qr-tree[lson].siz,rson);
mi=min(mi,t.first);
ma=max(ma,t.second);
}
return make_pair(mi,ma);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//===========================================================
read(n),read(m);
build(1,n,1);
while(m--){
int opt;read(opt);
if(opt==1){
int k;read(k);
eat(k,1);
}
if(opt==2){
int i,j;read(i),read(j);
pii ans=query(i,j,1);
write(ans.first),putchar(' '),write(ans.second),putchar('\n');
}
}
//===========================================================
return 0;
}D.瘦了的牛牛去旅游
这道题像不大明白Orz
首先看到数据范围,发现很小,又和最短路有关,我们想到的应该是Floyd。但这里求的是密度,我们还缺一个数,就是这条最短路他经过的路径数。俗话说的话:维度不够,再加一维?空间上也还可以,所以,我们就得到了整个状态dp[i][j][k],表示从i到j经过k条路径的最短路。这里其实算是一个分阶段贪心:对每个k,我们都选择i到j的最短路,记录下下来,然后,再遍历所有的k,选择其中最小的dp[i][j][k]/k作为ans[i][j]。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=((ans%mod)*(a%mod))%mod;
a=((a%mod)*(a%mod))%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxm=1e3+10;
const int maxn=55+10;
int n,m,q;
int G[maxn][maxn];
int dp[maxn][maxn][maxn];
double ans[maxn][maxn];
#include <iomanip>
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//===========================================================
read(n),read(m);
memset(G,inf,sizeof(G));
memset(dp,inf,sizeof(dp));
rep(i,0,n){
rep(j,0,n){
ans[i][j]=(double) inf;//ans是double型,需要手写循环初始化
}
}
while(m--){
int a,b,c;
read(a),read(b),read(c);
G[a][b]=min(G[a][b],c);
dp[a][b][1]=G[a][b];
}
rep(i,1,n) dp[i][i][0]=0;//边界条件
rep(l,2,n){//枚举经过的路径数
rep(k,1,n){//枚举中转结点
rep(i,1,n){//枚举起点
rep(j,1,n){//枚举中点
dp[i][j][l]=min(dp[i][j][l],dp[i][k][l-1]+G[k][j]);
}
}
}
}
rep(i,1,n){
rep(j,1,n){
rep(k,1,n){
if(dp[i][j][k]!=inf) ans[i][j]=min((1.0*dp[i][j][k])/k,ans[i][j]);//更新ans
}
}
}
int q;read(q);
while(q--){
int a,b;read(a),read(b);
if(ans[a][b]!=inf)cout<<fixed<<setprecision(3)<<ans[a][b]<<endl;
else puts("OMG!");
}
//===========================================================
return 0;
}E.只能吃土豆的牛牛
看到给的是3^n,就想到和二进制有关。我是这样想的:他要的是第k大,又是这样的3^n的形式,那么,可以看作是二进制串1、10、11……之间的大小比较,如,k=3,可以看作是第一小的1,第二小的10之后的第三小数11,这里的01串和这些土豆拿一部分出来的和是意义对应的,也就是说,一个二进制串可以对应某几个土豆的质量和,而二进制串的大小和土豆质量也是正相关的关系,所以,我们求第4大的土豆质量和,完全可以看到是100串,也就是这样取的结果(语无伦次)。所以,只需要对k进行二进制拆解就行了。
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
ll t,k;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(t);
int kase=0;
while(t--){
ll ans=0;
read(k);
ll base=1;
while(k){
if(k&1) ans+=base;
base*=3;
k>>=1;
}
printf("Case #%d: %lld\n",++kase,ans);
}
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
京公网安备 11010502036488号