A:
**题意: 给定三个数,要求变成另外三个数。有两个操作,①任选一个数 + 40,其他两个数 -20;②任选一个数 -40,其他两个数 +20. 输出最少的操作次数,无解输出-1.
思路: 直接bfs暴力骗分(bushi)
①衍化操作3.通过操作1和操作2,可以使得某个数+60,另一个数-60,剩余的不变。
②判断可行解:
可以简化操作,都除以20,就变成+2,-1,-1.
首先满足差值之和为0,dx + dy + dz = 0.
而且差值都是20的倍数。
而且需要 %3 同余,因为 2 == -1,1 == -2(模 3)
然后还是不会做。看了官方题解。
因为dx + dy + dz = 0,所以必定是一正两负或者两正一负。可以通过取负号变成一正两负。
那么就有 a < b < 0 < c.
先执行操作2,会导致b先到达0,至少是同时到达.因为操作不会改变三者的和,仍然是0.
那么就剩下a和c需要变了。此时满足-a = c且都是3的倍数,有解,否则无解。
可以证明-a = c,因为操作过程中三者的和不变,a + b + c = 0,b = 0.
可以证明a和c都是3的倍数。因为a、b、c在操作时始终%3相等,所以当b = 0,a和c%3也 = 0,都是3的倍数。
时间复杂度: O(1),思维题
代码:**
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<complex>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
#include<list>
#include<set>
#include<queue>
#include<stack>
#define OldTomato ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define p_ priority_queue
// round() 四舍五入 ceil() 向上取整 floor() 向下取整
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
// #define int long long //QAQ
using namespace std;
typedef complex<double> CP;
typedef pair<int,int> PII;
typedef long long ll;
// typedef __int128 it;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll inf = 1e18;
const int N = 2e5+10;
const int M = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-6;
inline int lowbit(int x){ return x&(-x);}
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 n,m,k,T;
void solve()
{
int x,y,z; int a,b,c;
cin>>a>>b>>c>>x>>y>>z;
int t1 = a - x;
int t2 = b - y;
int t3 = c - z;
if(t1 % 20 || t2 % 20 || t3 % 20 || t1+t2+t3 ) //预判
{
cout<<-1<<"\n";
return ;
}
else
{
t1 /= 20; t2 /= 20; t3 /= 20;
int tmp = (t1 % 3 + 3) % 3;
if((t2 % 3 + 3) % 3 != tmp || (t3 % 3 + 3) % 3 != tmp) //同余3后相等
{
cout<<-1<<"\n";
return ;
}
else
{
int tot = (t1 > 0) + (t2 > 0) + (t3 > 0);
if(tot == 2) t1 *= -1,t2 *= -1,t3 *= -1;
vector<int> va;
va.push_back(t1); va.push_back(t2); va.push_back(t3);
sort(va.begin(),va.end());
// for(int i=0;i<va.size();++i)
// {
// cout<<i<<" "<<va[i]<<endl;
// }
int ans = 0;
va[1] *= -1; //轮数
ans += va[1];
va[0] += va[1];
va[2] -= va[1] * 2;
ans += 2 * va[2] / 3;
cout<<ans<<"\n";
}
}
}
signed main(void)
{
// T = 1;
OldTomato; cin>>T;
// read(T);
while(T--)
{
solve();
}
return 0;
}
B:
题意: 01背包裸题,但是背包容量m很大,但是价值很小。
思路: ①两维互换,对于最大价值,看背包容积j最小取到多少,即是答案。
②赛场上的做法。对于m很大的情况,我直接贪心,按照性价比排序,从大到小装,当背包容积小于1e4的时候,对于剩余的物品套用01背包模板。n = 1e3,m = 1e4, O(nlogn + nm),可过。(代码比赛完不让看,不贴了,反正骗了满分。)
时间复杂度: O(nm’), O(nlogn + n*m’)
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<complex>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
#include<list>
#include<set>
#include<queue>
#include<stack>
#define OldTomato ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define p_ priority_queue
// round() 四舍五入 ceil() 向上取整 floor() 向下取整
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
// #define int long long //QAQ
using namespace std;
typedef complex<double> CP;
typedef pair<int,int> PII;
typedef long long ll;
// typedef __int128 it;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll inf = 1e18;
const int N = 2e5+10;
const int M = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-6;
inline int lowbit(int x){ return x&(-x);}
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;
}
#define int long long
int n,m,k,T;
int f[1001*30]; //价值不超过j,获得的最小的体积
int v[1001];
int w[1001];
int ans = 0;
void solve()
{
read(n); read(m);
int sum = 0;
int tot = 0;
for(int i=1;i<=n;++i)
{
read(v[i]);
sum += v[i];
}
fir(i,1,n) read(w[i]),tot += w[i];
if(m >= sum)
{
ans = tot;
write(ans); return ;
}
mem(f,0x3f);
f[tot] = sum;
// f[0] = 0x3f3f3f3f;
for(int i=1;i<=n;++i)
{
for(int j=tot;j>=w[i];--j)
{
f[j] = min(f[j],f[j-w[i]]+v[i]);
}
}
for(int i=tot;i>=0;--i)
{
// cout<<i<<":"<<f[i]<<endl;
if(f[i] <= m)
{
ans = i;
break;
}
}
write(ans);
}
signed main(void)
{
T = 1;
// OldTomato; cin>>T;
// read(T);
while(T--)
{
solve();
}
return 0;
}
C:
题意: 大模拟,敲了一小时没过样例。不做了,开摆。
D:
题意: 有n行m列的格子,构成一个地图。你有一个大本营,若干个防御堡垒,它们都有防御值s。有若干个僵尸队伍来打你的大本营,每个队伍有僵尸数量num.对于僵尸来说,他们走一个格子花费1秒;遇到一个堡垒时牺牲一个僵尸花费1秒,使该堡垒的防御值-1.当大本营被摧毁时,游戏结束,僵尸不再移动。所有僵尸队伍都会在开局选定一条伤亡最少的路线,如果路线有多条,选择最快到达的那条。要求输出最终的地图,如果大本营被摧毁,额外加一句"Game Over".
思路: 显然,可以把防御堡垒和大本营进行连边,对大本营跑一遍Dij,得到僵尸到它的最短路。然后僵尸按照这个最短路走。然后就是纯纯的模拟了,不多说。最后有一个点没过,因为防御堡垒剩余防御值 = 1,同时有三队僵尸,应该是三队都 -1,而不是第一个-1就把它摧毁了。懒得改了,敲就敲了半天。
时间复杂度: O(nm + VlogE),V = nm,E = V*4,需要先建边,n和m最大才100.也就是最多1e4个点。重点是模拟
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<complex>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
#include<list>
#include<set>
#include<queue>
#include<stack>
#define OldTomato ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define p_ priority_queue
// round() 四舍五入 ceil() 向上取整 floor() 向下取整
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
// #define int long long //QAQ
using namespace std;
typedef complex<double> CP;
typedef pair<int,int> PII;
typedef long long ll;
// typedef __int128 it;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll inf = 1e18;
const int N = 111;
const int M = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-6;
inline int lowbit(int x){ return x&(-x);}
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;
}
struct node{
int x,y; //去哪个边
int w; //边权
bool operator<(const node&rhs)
{
return w < rhs.w;
}
};
int n,m,k,T;
int a[111][111];
int sx,sy;
vector<node> va[111][111]; //存图
PII pre[N][N];
void init()
{
for(int i=0;i<=n+1;++i)
{
for(int j=0;j<=m+1;++j)
{
if(i-1 >= 1) va[i][j].push_back({i-1,j,a[i-1][j]});
if(i+1 <= n) va[i][j].push_back({i+1,j,a[i+1][j]});
if(j-1 >= 1) va[i][j].push_back({i,j-1,a[i][j-1]});
if(j+1 <= m) va[i][j].push_back({i,j+1,a[i][j+1]});
}
}
}
struct node3
{
int dis;
int x,y;
bool operator<(const node3&rhs)const
{
return dis > rhs.dis;
}
};
int dist[N][N];
bool vis[N][N];
void Dij()
{
for(int i=0;i<=105;++i)
{
for(int j=0;j<=105;++j)
{
pre[i][j] = {-1,-1};
dist[i][j] = 0x3f3f3f3f;
vis[i][j] = false;
}
}
dist[sx][sy] = 0;
priority_queue<node3> q;
q.push({0,sx,sy});
while(q.size())
{
auto tmp = q.top(); q.pop();
int x = tmp.x,y = tmp.y;
if(vis[x][y]) continue;
vis[x][y] = 1;
for(int i=0;i<va[x][y].size();++i)
{
int tx = va[x][y][i].x;
int ty = va[x][y][i].y;
// cout<<x<<" "<<y<<":"<<tx<<' '<<ty<<endl;
if(dist[tx][ty] > dist[x][y] + va[x][y][i].w)
{
dist[tx][ty] = dist[x][y] + va[x][y][i].w;
q.push({dist[tx][ty],tx,ty});
pre[tx][ty].first = x;
pre[tx][ty].second = y;
}
}
}
}
vector<node3> js; //僵尸
void solve()
{
cin>>n>>m>>k;
for(int i=0;i<n+2;++i)
{
for(int j=0;j<m+2;++j)
{
cin>>a[i][j];
if(a[i][j] < 0)
{
sx = i;
sy = j;
}
}
}
init();
// for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) sort(va[i][j].begin(),va[i][j].end());
Dij();
for(int i=1;i<n+1;++i)
{
if(a[i][0] > 0)
{
js.push_back({a[i][0],i,0});
pre[i][0].first = i;
pre[i][0].second = 1;
}
if(a[i][m+1] > 0)
{
js.push_back({a[i][m+1],i,m+1});
pre[i][m+1] = {i,m};
}
}
for(int j=1;j<=m;++j)
{
if(a[0][j] > 0)
{
js.push_back({a[0][j],0,j});
pre[0][j] = {1,j};
}
if(a[n+1][j] > 0)
{
js.push_back({a[n+1][j],n+1,j});
pre[n+1][j] = {n,j};
}
}
// cout<<js.size()<<"???"<<endl;
bool flag = false;
for(int t=1;t<=k;++t)
{
for(int i=0;i<js.size();++i)
{
if(js[i].dis == 0)
{
continue;
}
int x = js[i].x; int y = js[i].y;
int tx = pre[x][y].first;
int ty = pre[x][y].second;
// if(i == 0) cout<<js[i].dis<<"->"<<x<<' '<<y<<":"<<tx<<' '<<ty<<" "<<a[tx][ty]<<endl;
if(a[tx][ty] == 0)
{
js[i].x = tx;
js[i].y = ty;
}
else if(a[tx][ty] > 0)
{
js[i].dis -- ;
a[tx][ty] -- ;
}
else
{
a[tx][ty] ++ ;
js[i].dis -- ;
}
}
if(a[sx][sy] >= 0)
{
flag = true;
break;
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(j > 1) cout<<' ';
cout<<a[i][j];
}
cout<<"\n";
}
if(flag) cout<<"Game Over";
}
signed main(void)
{
T = 1;
// OldTomato; cin>>T;
// read(T);
while(T--)
{
solve();
}
return 0;
}