杭电杯第一场
大约 6 分钟
杭电杯第一场
个人题解,欢迎指正
P1002
题目大意:
给定网格大小,起点和终点,求到达终点的最小摧毁墙的数量
思路:
由于数据范围较小,我们可以枚举剩余的墙然后再跑或,时间复杂度
墙在网格线上,走的是格子,我们可以把网格大小扩大一倍,使得路径和墙都在网格上
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define lowbit(x) ((x)&(-x))
#define fi first
#define se second
#define pb push_back
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
x *= f;
}
int main()
{
int T;
read(T);
while (T--)
{
int n,m,k;
read(n),read(m),read(k);
int xs,ys,xt,yt;
n = n * 2,m = m * 2;//扩大两倍
read(xs),read(ys),read(xt),read(yt);
xs = xs * 2 + 1,ys = ys * 2 + 1,xt = xt * 2 + 1,yt = yt * 2 + 1;//扩大两倍(原点)
vector<pair<pii,pii>> query(k + 1);
for(int i = 1;i <= k;i++)
{
int xl,yl,xr,yr;
read(xl),read(yl),read(xr),read(yr);
xl = xl * 2,yl = yl * 2,xr = xr * 2,yr = yr * 2;//扩大两倍
query[i] = {{xl,yl},{xr,yr}};//记录墙
}
bool st[17] = {0};
int ans = k;
auto bfs = [&](int cnt) -> void
{
bool ok = false;
bool S[50][50] = {0};
for(int i = 1;i <= k;i++)//预处理
{
if(st[i]) continue;
if(query[i].fi.fi == query[i].se.fi)//横轴相等
{
int mi = min(query[i].fi.se,query[i].se.se),mx = max(query[i].fi.se,query[i].se.se);
for(int k = mi;k <= mx;k++) S[query[i].fi.fi][k] = true;
}
else//纵轴相等
{
int y = query[i].fi.se;
int mi = min(query[i].fi.fi,query[i].se.fi),mx = max(query[i].fi.fi,query[i].se.fi);
for(int k = mi;k <= mx;k++) S[k][y] = true;
}
}
queue<pii> q;
q.push({xs,ys});
bool stt[50][50] = {0};
while (q.size())
{
auto t = q.front();
q.pop();
if(stt[t.fi][t.se]) continue;
stt[t.fi][t.se] = true;
int dx[] = {-2,0,2,0},dy[] = {0,2,0,-2};//左,上,右,下
for(int i = 0;i < 4;i++)
{
int nx = t.first + dx[i],ny = t.second + dy[i];
if(nx >= 0 && nx < n && ny >= 0 && ny < m)
{
if(!i || i == 2)
{
if(!S[t.fi + dx[i] / 2][ny] && !stt[nx][ny]) q.push({nx,ny});
}
else
{
if(!S[nx][t.se + dy[i] / 2] && !stt[nx][ny]) q.push({nx,ny});
}
}
}
}
if(stt[xt][yt]) ok = true;
else ok = false;
if(ok) ans = min(ans,cnt);
};
for(int i = 0;i < 1 << k;i++)
{
memset(st,0,sizeof(st));
int cnt = 0;
for(int j = 0;j < k;j++)
{
if(i >> j & 1)
{
st[j + 1] = true;
cnt++;
}
}
bfs(cnt);
}
printf("%d\n",ans);
}
return 0;
}
P1009
题目大意:
给定个点,判断这个点是否能构成一个“米”字型
思路:
首先确定一个点为中心,遍历其他点,找到一个不在此“米”字上的一个点,然后就可以根据这两个点确定“米”字型,情况数种,然后分别遍历判断是否有其他点不在“米”字上
tip:只用求出种情况的坐标,因为只用把两个点交换就可以得到另外个点的坐标
Code:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define WA return 0;
#define ptn putchar('\n')
using namespace std;
inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
const double INF=0x3f3f3f3f;
int n;
double asd(double x){
return x<0?-x:x;
}
const double dsa=1e-9;
bool che(pair<double,double>&a,pair<double,double>&b){
if(asd(a.first-b.first)<dsa)return 1;
if(asd(a.second-b.second)<dsa)return 1;
if(asd(asd(a.first-b.first)-asd(a.second-b.second))<dsa)return 1;
return 0;
}
vector<pair<double,double>>a(n+1);
bool judge(pair<double,double>ha){
for (int i = 1; i <= n; i++)
{
if(!che(ha,a[i])){
return 0;
}
}
return 1;
}
void Qingtuan(){
n=read();
a.resize(n+1);
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf",&a[i].first,&a[i].second);
}
bool ju=1;
pair<double,double>h;
for (int i = 2; i <= n; i++)
{
if(!che(a[1],a[i])){ //找出一个不在以a[1]为中心的“米”字的点
ju=0;
h=a[i];break;
}
}
if(ju){
puts("YES");return;
}
pair<double,double>p,q,ha;
p=a[1];q=h;
//1
if(judge({q.first,p.second})){
puts("YES");return;
}
swap(p,q);
if(judge({q.first,p.second})){
puts("YES");return;
}
//2
if(judge({q.first-q.second+p.second,p.second})){
puts("YES");return;
}
swap(p,q);
if(judge({q.first-q.second+p.second,p.second})){
puts("YES");return;
}
//3
if(judge({q.first+q.second-p.second,p.second})){
puts("YES");return;
}
swap(p,q);
if(judge({q.first+q.second-p.second,p.second})){
puts("YES");return;
}
//4
if(judge({p.first,q.first-p.first+q.second})){
puts("YES");return;
}
swap(p,q);
if(judge({p.first,q.first-p.first+q.second})){
puts("YES");return;
}
//5
if(judge({p.first,q.second-q.first+p.first})){
puts("YES");return;
}
swap(p,q);
if(judge({p.first,q.second-q.first+p.first})){
puts("YES");return;
}
//6
if(judge({(p.first+q.first+q.second-p.second)/2,(p.second+q.first+q.second-p.first)/2})){
puts("YES");return;
}
swap(p,q);
if(judge({(p.first+q.first+q.second-p.second)/2,(p.second+q.first+q.second-p.first)/2})){
puts("YES");return;
}
puts("NO");
}
int main(){
//cin.tie(nullptr)->sync_with_stdio(false);
int T=read();while (T--)
Qingtuan();
WA
}
P1011
题目大意:
在之间随机生成个数,然后分别有一半的可能去掉个最大或最小的数,求最后剩余数字和的期望
思路:
因为数字大小概率相等,所以生成数字的均值为,去掉个最大最小的数均值也为,所以最后结果为,因为是对取模,只需要处理一下的逆元即可
Code:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define WA return 0;
#define ptn putchar('\n')
using namespace std;
inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
ll mod=1e9+7;
inline ll fp(ll x, ll y) {
ll base = 1;
while (y)
{
if (y&1)
base =base*x%mod;
x=x*x%mod;y >>= 1;
}
return base;
}
ll n,m;
ll inv2;
void Qingtuan(){
n=read();m=read();
writ((n-m)*inv2%mod);ptn;
}
int main(){
//cin.tie(nullptr)->sync_with_stdio(false);
inv2=fp(2,mod-2);
int T=read();while (T--)
Qingtuan();
WA
}
P1012
题目大意:
可以把一堆数分成两堆,可以选择一堆并擦去,剩余一堆数字减半,当黑板上出现则胜出,黑板上数字都被擦完了则胜出
思路:
首先分析两种最简单的情况
黑板上有或只有一个时,必胜
黑板上有两个时,必胜
我们尝试将数字全部转化为的个数来进行判断,举个例子:
黑板上为时候,分为和,此时必胜
假如只有,当的个数为及以上时,必胜
假如只有,当的个数为及以上时,必胜
我们发现,当一个数为的时候,对的贡献为 ,对的贡献为 ,此时就可以把每个数转化为的个数来进行判断
可以将贡献理解为相当于,比如两个就相当于一个
Code:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define WA return 0;
#define ptn putchar('\n')
using namespace std;
inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
ll n;
void Qingtuan(){
n=read();
vector<ll>a(n+1);
for (int i = 0; i <= n; i++)
{
a[i]=read();
}
if(a[0]){
puts("Alice");return;
}
for (int i = n; i >1; i--)
{
a[i-1]+=a[i]>>1;
}
if(a[1]>=2)
puts("Alice");
else
puts("Bob");
}
int main(){
//cin.tie(nullptr)->sync_with_stdio(false);
int T=read();while (T--)
Qingtuan();
WA
}