2021浙江省赛题解(A,C,F,G,J,L,M)
A.League of Legends
题解
签到题
直接求和判断一下
注意会爆 i n t int int以及相等的情况。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[10],b[10];
void solve(){
rp(i,1,5) a[i]=read();
rp(i,1,5) b[i]=read();
ll sum1=0,sum2=0;
rp(i,1,5) sum1+=a[i],sum2+=b[i];
if(sum1<sum2) cout<<"Red"<<endl;
else cout<<"Blue"<<endl;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
C.Cube
题解
刚开始以为题意是判断是否是长方体。
然后写了长方体的判断方法,后面看样例发现是正方体后想到一个简单做法。
判断是否有 12 12 12个相等的棱, 12 12 12个相等的面对角线, 4 4 4个相等的体对角线,以及棱,面对角线和体对角线可以形成直角三角形(满足勾股定理)就行了。
代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
LL read() {
LL x(0), f(1); char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
struct poi {
int x, y, z;
poi(){}
poi(int x, int y, int z):x(x), y(y), z(z) {}
void sc() {
x = read(), y = read(), z = read();
}
bool operator<(const poi b) const {
if(x != b.x) return x < b.x;
if(y != b.y) return y < b.y;
if(z != b.z) return z < b.z;
return 0;
}
};
int T;
vector<poi> a;
set<poi> a4, ano4;
LL MaxDis;
int isEqu(LL a, LL b) {
return a == b;
}
LL getDis(poi a, poi b) {
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z);
}
int isSqu(poi a, poi b, poi c, poi d) {
vector<poi> t;
t.push_back(a);
t.push_back(b);
t.push_back(c);
t.push_back(d);
vector<LL> vals;
_for(i, 4) {
_for(j, i) {
vals.push_back(getDis(t[i], t[j]));
}
}
sort(vals.begin(), vals.end(), greater<LL>());
if(isEqu(vals[0], vals[2])) return 0;
if(isEqu(vals[0], MaxDis)) return 0;
if(!isEqu(vals[0], vals[1])) return 0;
if(!isEqu(vals[2], vals[3])) return 0;
if(!isEqu(vals[4], vals[5])) return 0;
if(!isEqu(vals[4], vals[2])) return 0;
return 1;
}
set<poi> getSqu() {
set<poi> ans;
_for(i, 8) {
_for(j, i) {
_for(k, j) {
_for(l, k) {
if(isSqu(a[i], a[j], a[k], a[l])) {
ans.insert(a[i]);
ans.insert(a[j]);
ans.insert(a[k]);
ans.insert(a[l]);
return ans;
}
}
}
}
}
return ans;
}
LL getMinDis(poi a) {
LL ans = INF;
for(poi i : ano4) {
ans = min(getDis(a, i), ans);
}
return ans;
}
void init() {
MaxDis = -1;
a4.clear();
ano4.clear();
}
int sol() {
init();
_for(i, 8) {
_for(j, i) {
if(!(a[i] < a[j]) && !(a[j] < a[i])) return 0;
}
}
vector<LL> diss;
_for(i, 8) {
_for(j, i) {
diss.push_back(getDis(a[i], a[j]));
}
}
sort(diss.begin(), diss.end());
_for(i, 12) {
_for(j, i) {
if(diss[i] != diss[j]) return 0;
}
}
_for(i, 12) {
_for(j, i) {
if(diss[12 + i] != diss[12 + j]) return 0;
}
}
_for(i, 4) {
_for(j, i) {
if(diss[24 + i] != diss[24 + j]) return 0;
}
}
if(diss[0] + diss[12] != diss[24]) return 0;
return 1;
}
int main() {
// freopen("in.txt", "r", stdin);
scanf("%d", &T);
_for(i, T) {
a.resize(8);
_for(i, 8) a[i].sc();
printf("%s\n", sol() ? "YES":"NO");
}
return 0;
}
F.Fair Distribution
题解
不难发现对于
n
>
m
n>m
n>m的情况直接输出
n
−
m
n-m
n−m即可。
对于其他的情况我们可以推出一个公式。
推导过程如下:
我们假设
n
n
n减小成了
i
i
i(
1
≤
i
≤
n
1 \leq i \leq n
1≤i≤n)
那么这是 m m m就需要变成 ⌈ m i ⌉ ∗ i \lceil \frac{m}{i} \rceil*i ⌈im⌉∗i。
操作次数就是 n − i + ⌈ m i ⌉ ∗ i − m n-i+\lceil \frac{m}{i} \rceil*i-m n−i+⌈im⌉∗i−m。
整理可得原式等于
(
⌈
m
i
⌉
−
1
)
∗
i
+
n
−
m
(\lceil \frac{m}{i} \rceil-1)*i+n-m
(⌈im⌉−1)∗i+n−m
我们把上式中的上取整转换成下取整。
( ⌊ m + i − 1 i ⌋ − 1 ) ∗ i + n − m (\lfloor \frac{m+i-1}{i} \rfloor-1)*i+n-m (⌊im+i−1⌋−1)∗i+n−m
⇉ ⌊ m − 1 i ⌋ ∗ i + n − m \rightrightarrows \lfloor \frac{m-1}{i} \rfloor*i+n-m ⇉⌊im−1⌋∗i+n−m
这时我们就可分块维护 ⌊ m − 1 i ⌋ ∗ i \lfloor \frac{m-1}{i} \rfloor*i ⌊im−1⌋∗i,记录答案最小值就行了。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
ll n,m;scl(n);scl(m);
if(n>m) cout<<n-m<<endl;
else{
ll ans=inf;
for(ll l=1,r;l<=n;l=r+1){
r=min(n,(m-1)/((m-1)/l));
ans=min(ans,(m-1)/l*l);
}
cout<<ans+n-m<<endl;
}
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
int T=read();
while(T--) solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
G.Wall Game
题解
把每个坐标离散化成一个点。
对于每次占领操作,我们用并查集维护能够触碰的墙的个数。
对于一个坐标,最多能和六个相邻的坐标相连,我们枚举相邻几个个点能够触碰的墙的和 s u m sum sum以及自身产生的能够触碰的墙的个数 6 6 6。
然后用容斥的思想减去需要消去的墙的个数。
这时分为两种来考虑。
一种是自身和相邻坐标消去的墙 c n t cnt cnt,
另一种是相邻坐标中中消去的墙 m i n u s minus minus(其祖先节点不相等)。
注意需要判断相邻坐标祖先节点相同时的情况(去重),
最终该点的答案就是 s u m − 6 − c n t ∗ 2 − m i n u s ∗ 2 sum-6-cnt*2-minus*2 sum−6−cnt∗2−minus∗2。
对于每次查询操作,查询其祖先节点的答案即可。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 5e5+7;
int fa[N];
int w[N];
map<pii,int> mp;
int dir[6][2]={0,1,1,0,1,-1,0,-1,-1,0,-1,1};
int find(int x){
return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
void solve(){
int n=read();
int tot=0;
while(n--){
int op=read(),x=read(),y=read();
if(op==1){
mp[m_p(x,y)]=++tot;
fa[tot]=tot;
w[tot]=6;
int sum=0;
int minus=0;
int cnt=0;
set<int> ss;
vector<pii> vv;
rp(k,0,5){
int nx=x+dir[k][0];
int ny=y+dir[k][1];
if(mp.find(m_p(nx,ny))==mp.end()) continue;
int id=find(mp[m_p(nx,ny)]);
vv.push_back(m_p(k,id));
if(ss.find(id)!=ss.end()) cnt++;
else{
cnt++;
sum+=w[id];
ss.insert(id);
}
}
int len=vv.size();
rp(k,0,len-1){
rp(j,0,len-1){
if(vv[k].first==0&&vv[j].first==1&&vv[k].second!=vv[j].second) minus++;
if(vv[k].first==1&&vv[j].first==2&&vv[k].second!=vv[j].second) minus++;
if(vv[k].first==2&&vv[j].first==3&&vv[k].second!=vv[j].second) minus++;
if(vv[k].first==3&&vv[j].first==4&&vv[k].second!=vv[j].second) minus++;
if(vv[k].first==4&&vv[j].first==5&&vv[k].second!=vv[j].second) minus++;
if(vv[k].first==5&&vv[j].first==0&&vv[k].second!=vv[j].second) minus++;
}
}
for(auto val:ss){
// cout<<val<<" ";
fa[val]=tot;
}
// cout<<endl;
w[tot]=sum+w[tot]-2*cnt-2*minus;
// cout<<w[tot]<<endl;
// outval3(sum,cnt,minus);
}
else{
cout<<w[find(mp[m_p(x,y)])]<<endl;
}
}
// for(auto val:mp){
// pii t=val.first;
// outval3(t.first,t.second,find(mp[t]));
// }
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
J.Grammy and Jewelry
题解
算是比较套路的题。
根据贪心的原则,我们每次取一个宝珠后应该立马返回到原点。
而我们到这个宝珠的位置走的路和返回时走的路应该是最短路。
转换一下就是我们要取一个价值为 a [ i ] a[i] a[i]的宝珠,需要消耗容量为 2 ∗ d i s [ i ] 2*dis[i] 2∗dis[i]的时间( d i s [ i ] dis[i] dis[i]表示从 1 1 1到 i i i的最短路)。
这样就转换成了经典的完全背包问题。
关于背包问题不懂的可以看经典的背包九讲。
代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
#define INF 0x3f3f3f3f
const int N = 3007;
using namespace std;
LL read() {
LL x(0), f(1); char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
vector<int> G[N];
int a[N];
int dis[N];
int vis[N];
int dp[N];
struct node{
int u,w;
friend bool operator <(node a,node b){
return a.w>b.w;
}
};
int n,m,T;
void Dijkstra(){
priority_queue<node> q;
_rep(i,1,n) dis[i]=0x3f3f3f3f;
q.push(node{1,0});
dis[1]=0;
memset(vis,0,sizeof vis);
while(!q.empty()){
node t=q.top();
q.pop();
vis[t.u]=1;
int u=t.u;
int w=t.w;
// cout<<u<<" "<<w<<endl;
for(auto v:G[u]){
// cout<<v<<" "<<dis[v]<<endl;
if(!vis[v]&&dis[v]>w+1){
dis[v]=w+1;
q.push(node{v,dis[v]});
}
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
n=read(),m=read(),T=read();
_rep(i,2,n) a[i]=read();
_rep(i,1,m){
int u=read(),v=read();
if(u==v) continue;
G[u].push_back(v);
G[v].push_back(u);
}
// for(int u=1;u<=n;u++){
// cout<<u<<endl;
// for(auto v:G[u]) cout<<v<<" ";
// cout<<endl;
// }
Dijkstra();
// _rep(i, 1, n) printf("dis[%d]:%d\n", i, dis[i]);
_rep(i, 1, n) {
for(int j = dis[i] * 2; j <=T ; ++j) {
dp[j] = max(dp[j], dp[j - dis[i] * 2] + a[i]);
}
}
_rep(i, 1, T) printf("%d%s", dp[i], (i == T ? "\n":" "));
return 0;
}
L.String Freshman
题解
c f cf cf上的题意有点错误,给的字符串应该是匹配串。
因此我们判断一下是否存在前缀子串的最长公共前后缀长度不为 0 0 0(即next数组不为 0 0 0)。
更简单的做法就是判断是否有字符和第一个字符相等即可。
代码
#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
inline int read(){
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
int n=read();
string s;cin>>s;
rp(i,1,n-1){
if(s[i]==s[0]){
printf("Wrong Answer\n");
return ;
}
}
printf("Correct\n");
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
//debug = 1;
#endif
//time_t beg, end;
//if(debug) beg = clock();
solve();
/*
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
*/
return 0;
}
M.Game Theory
题解
假结论题。
先说结论:输出 0.0000 0.0000 0.0000即可。
当时感觉题意有点模糊,后面读懂题意后验证了一下就交了。
首先我们知道每个学生是不知道 G r a m m y Grammy Grammy的选择,而又因为学生每次都是最优的选择,因此我们可以先算出一个学生在 [ 1 , 20 ] [1,20] [1,20]选择一个数后赢的分数的期望,每次都选择这 20 20 20个数中期望最大的即可。
我们写出计算期望的代码可以发现,每个数赢的分数的期望都是 0 0 0。
而学生和 G r a m m y Grammy Grammy的分数又是互补的,只有一个输了,另一个才能赢。
因此 G r a m m y Grammy Grammy赢的分数的期望也是 0 0 0。
代码
#include <bits/stdc++.h>
#define _for(i, a) for(int i = 0, le = (a); i < le; ++i)
#define _rep(i, a, b) for(int i = (a), le = (b); i <= le; ++i)
typedef long long LL;
using namespace std;
LL read() {
LL x(0), f(1); char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int maxn = 100005;
int getSco(int G, int S) {
if(G > S) return G - S - 10;
if(S > G) return G - S + 10;
return G - S;
}
double sco(int x) {
double ans = 0;
_rep(i, 1, 20) {
ans += getSco(i, x);
}
return ans / 20.0;
}
int main() {
// _rep(i, 1, 20) {
// printf("i:%d\tans:%.10f\n", i, sco(i));
// }
int x = read();
printf("0.0000\n");
return 0;
}