Preface
徐神在训练前宣称要复习计通网,结果最后还是相当于全程参与了我们的训练
这场我纯纯战犯表现,Easy题E狂挂7发最后发现原来是多测没清空干净,直接红温占用中期1h机时
但好在祁神稳切了一手压轴计算几何,同时最后2h把卡着的题都过完了,最后又靠着题数捧杯(唉还在打弱省省赛找自信)
A. 小水獭游河南
签到,枚举最后合法的前缀然后暴力检验即可,因为合法的前缀个数最多只有\(26\)种因此复杂度不会爆
然后因为没看清两个字符串都要非空还WA了一发
#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int t,n; char s[N];
int main()
{
//freopen("A.in","r",stdin); freopen("A.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; scanf("%s",s+1); n=strlen(s+1);
static int vis[30]; for (i=0;i<26;++i) vis[i]=0;
bool sign=0; for (i=1;i<n;++i)
{
if (vis[s[i]-'a']) break; vis[s[i]-'a']=1;
bool flag=1; for (RI l=i+1,r=n;l<=r;++l,--r)
if (s[l]!=s[r]) { flag=0; break; }
if (flag) { sign=1; break; }
}
puts(sign?"HE":"NaN");
}
return 0;
}
B. Art for Rest
暴力枚举\(k\),用调和级数的复杂度大力检验是否合法即可
只要比对前一块的最大值是否小于等于后一块的最小值即可,用个ST表维护下,复杂度\(O(n\log n)\)
#include<cstdio>
#include<iostream>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1e6+5,INF=1e9;
int n,a[N],mn[N][25],mx[N][25],lg[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
inline int query_min(CI l,CI r)
{
int k=lg[r-l+1]; return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
inline int query_max(CI l,CI r)
{
int k=lg[r-l+1]; return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int main()
{
//freopen("B.in","r",stdin); freopen("B.out","w",stdout);
RI i,j; for (F.read(n),i=1;i<=n;++i) F.read(a[i]),mn[i][0]=mx[i][0]=a[i];
for (lg[0]=-1,i=1;i<=n;++i) lg[i]=lg[i>>1]+1;
for (j=1;(1<<j)<=n;++j) for (i=1;i+(1<<j)-1<=n;++i)
mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]),
mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
int ans=0; for (j=1;j<=n;++j)
{
bool flag=1; int MX=-INF;
for (i=1;i<=n;i+=j)
{
int pos=min(i+j-1,n),cmn=query_min(i,pos);
if (MX>cmn) { flag=0; break; }
MX=query_max(i,pos);
}
ans+=flag;
}
return printf("%d",ans),0;
}
C. Toxel 与随机数生成器
趣味题,被徐神一眼秒了
不难发现如果用的是错误的随机生成器,那么对其求Z函数就会出现\(1000\)以上的值
而随机生成得到的要有这么长的公共前缀概率是\(\frac{1}{2^{1000}}\),显然不可能
同时由于随机的性质我们不需要真的去写Z函数/Hash,可以直接暴力判断
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1e6;
char s[N+5];
int main()
{
RI i,j,k; scanf("%s",s+1); bool flag=1;
for (i=2;i<=N;++i)
{
for (j=1,k=i;j<=N&&k<=N;++j,++k)
if (s[j]!=s[k]) break;
if (j-1>=1000) { flag=0; break; }
}
return puts(flag?"Yes":"No"),0;
}
D. Toxel 与多彩的宝可梦世界
防AK论文题,做不了一点
E. 矩阵游戏
最红温的一集,因为想卡个cache因此让徐神教了我一种新的滚存的写法,结果因为不熟悉清空没清干净把心态搞炸了
这题做法很简单,直接暴力DP,\(f_{i,j,k}\)表示走到\((i,j)\),将\(k\)个?
改成1
后能得到的最大得分,转移显然
但直接这么做时间复杂度虽然没问题但会爆空间,因此需要滚存一下,按照斜对角线的转移顺序将\(i+j\)的和按顺序滚存即可
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=505;
int t,n,m,cs,f_base[2][N][N<<1]; char s[N][N];
auto f0 = f_base[0];
auto f1 = f_base[1];
int main()
{
//freopen("E.in","r",stdin); freopen("E.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j,k; for (scanf("%d%d%d",&n,&m,&cs),i=1;i<=n;++i) scanf("%s",s[i]+1);
for (j=0;j<=n;++j) for (k=0;k<=cs;++k) f0[j][k]=f1[j][k]=0;
if (s[1][1]=='?') f0[1][1]=1; else f0[1][0]=(s[1][1]=='1');
for (i=3;i<=n+m;++i)
{
for (j=1;j<=min(i,n);++j)
{
int x=j,y=i-j; if (x<1||x>n||y<1||y>m) continue;
for (k=0;k<=min(i,cs);++k)
{
f1[j][k]=0;
if (s[x][y]=='?')
{
if (x-1>0) f1[j][k]=max(f1[j][k],f0[j-1][k]);
if (y-1>0) f1[j][k]=max(f1[j][k],f0[j][k]);
if (x-1>0&&k) f1[j][k]=max(f1[j][k],f0[j-1][k-1]+1);
if (y-1>0&&k) f1[j][k]=max(f1[j][k],f0[j][k-1]+1);
} else
{
if (x-1>0) f1[j][k]=max(f1[j][k],f0[j-1][k]+(s[x][y]=='1'));
if (y-1>0) f1[j][k]=max(f1[j][k],f0[j][k]+(s[x][y]=='1'));
}
//printf("f[%d][%d][%d] = %d\n",x,y,k,f1[j][k]);
}
}
swap(f0,f1);
}
int ans=0; for (k=0;k<=cs;++k) ans=max(ans,f0[n][k]);
printf("%d\n",ans);
}
return 0;
}
F. Art for Last
祁神开场写的,我题目都没看
#include<bits/stdc++.h>
#define int long long
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
const int INF = (int)1e18+5;
const int N = 1e6+5;
int n, k, A[N], B[N];
signed main()
{
//freopen("F.in","r",stdin); freopen("F.out","w",stdout);
F.read(n); F.read(k);
for (int i=1; i<=n; ++i) F.read(A[i]);
sort(A+1, A+n+1);
for (int i=1; i<n; ++i) B[i]=A[i+1]-A[i];
multiset<int> st;
int ans=INF;
for (int i=1; i<=n; ++i){
if (i>=k){
ans = min(ans, (*st.begin())*(A[i]-A[i-k+1]));
st.erase(st.find(B[i-k+1]));
}
if (i<n) st.insert(B[i]);
}
printf("%lld\n", ans);
return 0;
}
G. Toxel 与字符画
构式模拟题,因为我当时有点红温就扔给祁神写了,祁神也是不负众望瞬秒了此题
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1e18;
char *tbl[3][10] = {
{
"................................................................................",
"................................................................................",
"0000000.......1.2222222.3333333.4.....4.5555555.6666666.7777777.8888888.9999999.",
"0.....0.......1.......2.......3.4.....4.5.......6.............7.8.....8.9.....9.",
"0.....0.......1.......2.......3.4.....4.5.......6.............7.8.....8.9.....9.",
"0.....0.......1.2222222.3333333.4444444.5555555.6666666.......7.8888888.9999999.",
"0.....0.......1.2.............3.......4.......5.6.....6.......7.8.....8.......9.",
"0.....0.......1.2.............3.......4.......5.6.....6.......7.8.....8.......9.",
"0000000.......1.2222222.3333333.......4.5555555.6666666.......7.8888888.9999999.",
"................................................................................",
},
{
"............................................................",
"00000.....1.22222.33333.4...4.55555.66666.77777.88888.99999.",
"0...0.....1.....2.....3.4...4.5.....6.........7.8...8.9...9.",
"0...0.....1.22222.33333.44444.55555.66666.....7.88888.99999.",
"0...0.....1.2.........3.....4.....5.6...6.....7.8...8.....9.",
"00000.....1.22222.33333.....4.55555.66666.....7.88888.99999.",
"............................................................",
"............................................................",
"............................................................",
"............................................................",
},
{
"................................",
"................................",
"........IIIIIII.N.....N.FFFFFFF.",
"...........I....NN....N.F.......",
"=======....I....N.N...N.F.......",
"...........I....N..N..N.FFFFFFF.",
"=======....I....N...N.N.F.......",
"...........I....N....NN.F.......",
"........IIIIIII.N.....N.F.......",
"................................",
},
};
char ans[10][5000]; int pos;
void putsdn(int x){
for (int i=0; i<10; ++i){
for (int j=0; j<8; ++j){
ans[i][pos+j] = tbl[0][i][x*8+j];
}
}
pos += 8;
}
void putsup(int x){
for (int i=0; i<10; ++i){
for (int j=0; j<6; ++j){
ans[i][pos+j] = tbl[1][i][x*6+j];
}
}
pos += 6;
}
void putseq(){
for (int i=0; i<10; ++i){
for (int j=0; j<8; ++j){
ans[i][pos+j] = tbl[2][i][j];
}
}
pos += 8;
}
void putsINF(){
for (int i=0; i<10; ++i){
for (int j=8; j<32; ++j){
ans[i][pos+j-8] = tbl[2][i][j];
}
}
pos += 24;
}
void putsnum(int x, int typ){
vector<int> vec;
while (x>0){
vec.push_back(x%10);
x/=10;
}
for (auto it=vec.rbegin(); it!=vec.rend(); ++it){
if (1==typ) putsdn(*it);
else putsup(*it);
}
}
int calc(int x, int y){
if (1==x) return x;
__int128 res=1;
while (y>0){
res *= x;
--y;
if (res>INF) return -1;
}
return res;
}
signed main(){
// ios::sync_with_stdio(0); cin.tie(0);
for (int i=0; i<10; ++i) ans[i][0]='.';
int t; scanf("%lld", &t);
while (t--){
int x, y; scanf("%lld^{%lld}", &x, &y);
pos=1;
putsnum(x, 1); putsnum(y, 2);
putseq();
int res=calc(x, y);
if (-1==res) putsINF();
else putsnum(res, 1);
// printf("pos=%lld\n", pos);
for (int i=0; i<10; ++i){
ans[i][pos]=0;
// puts(ans[i]);
for (int j=0; j<pos; ++j) putchar(ans[i][j]); puts("");
}
if (t) puts("");
}
return 0;
}
H. Travel Begins
经典因为没特判扔了好久,后面仔细一想原来没考虑\(k>2n\)的情况
最大值的话就考虑先把前\(k-1\)个位置都放上\(0.5\),然后剩下的数都放最后一个位置
最小值的话同理,先在前面\(k-1\)个位置放\(0.5-\epsilon\),剩下的数放在最后即可,但要注意一下Corner Case
#include<bits/stdc++.h>
#define int long long
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
int t, n, k;
signed main(){
//freopen("H.in","r",stdin); freopen("H.out","w",stdout);
F.read(t);
while (t--){
F.read(n), F.read(k);
int mn = max(n-(k-1)/2, 0LL);
int mx = min(n-(k+1)/2+k, 2*n);
printf("%lld %lld\n", mn, mx);
}
return 0;
}
I. 数正方形
第一眼看很难,仔细一想很简单的一个题
首先容斥一下,用总的\(2\times 2\)正方形个数减去不纯色的正方形个数
不难发现当一个\(2\times 2\)正方形的中心点被任意一个矩形的边经过时,这个正方形就一定不合法了,因此问题转化为统计被至少一条边经过的格点数
不妨再容斥下,因为这题的特殊性质,每个格点最多被两条边经过,因此我们用所有边的边长和减去交点个数即可
这个是个很经典的扫描线问题,用一个树状数组即可维护
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,x_1,y_1,x_2,y_2,L[N],R[N];
class Tree_Array
{
private:
int bit[N];
public:
#define lowbit(x) (x&-x)
inline int get(RI x,int ret=0)
{
for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
}
inline void add(RI x,CI y)
{
for (;x<=2*n;x+=lowbit(x)) bit[x]+=y;
}
#undef lowbit
}BIT;
int main()
{
//freopen("I.in","r",stdin); freopen("I.out","w",stdout);
RI i; scanf("%d",&n); long long ans=4LL*n*n;
for (i=1;i<=n;++i)
{
scanf("%d%d%d%d",&x_1,&y_1,&x_2,&y_2);
ans-=2LL*(x_2-x_1+y_2-y_1+1);
L[x_1]=y_1; R[x_1]=y_2; L[x_2]=-y_1; R[x_2]=-y_2;
}
for (i=1;i<=2*n;++i)
{
auto sgn=[&](CI x)
{
return x>0?1:-1;
};
ans+=BIT.get(abs(R[i]))-BIT.get(abs(L[i])-1);
BIT.add(abs(L[i]),sgn(L[i])); BIT.add(abs(R[i]),sgn(R[i]));
}
return printf("%lld",ans),0;
}
J. Mocha 沉迷电子游戏
经典计算几何,但是我们有祁神,虽然我连题意都不知道,但我们队就是能一发过这个题,自信.jpg
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define LD long double
const LD eps = 1e-8;
const LD PI = acos(-1.0L);
#define RI register int
#define CI const int&
#define Tp template <typename T>
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; int flag=1; while (!isdigit(ch=tc())) if (ch=='-') flag=-1;
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); x*=flag;
}
#undef tc
}F;
int sgn(LD x){return fabs(x)<=eps ? 0 : (x > eps ? 1 : -1);}
struct Pt{
int x, y;
int crs(Pt b){return x*b.x-y*b.x;}
int dis2(Pt b){return (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y);}
};
signed main(){
// freopen("J.in", "r", stdin);
int T; F.read(T);
while (T--){
Pt A, B, P;
int v, t, R;
F.read(P.x); F.read(P.y);
F.read(A.x); F.read(A.y);
F.read(B.x); F.read(B.y);
F.read(v); F.read(t);
R=v*t;
int AB2 = A.dis2(B); LD AB = sqrtl(AB2);
int PA2 = P.dis2(A); LD PA = sqrtl(PA2);
int R2 = R*R;
LD dl2 = PA2 - 0.25L*(AB2); LD dl = sqrtl(dl2);
LD sint2 = 1.0L*R2/PA2;
LD cost2 = 1.0L - sint2;
LD cost = sqrtl(cost2);
// printf("R=%lld AB2=%lld AB=%Lf PA=%Lf dl=%Lf cost2=%Lf cost=%Lf\n", R, AB2, AB, PA, dl, cost2, cost);
LD ans = 0.0L;
if (sgn(dl2-R2) >= 0){ //圆与直线不相交
LD alpha = acos(dl/PA);
LD theta = PI*0.5L - acos(cost);
LD beta = PI - alpha - theta;
// printf("alpha=%Lf theta=%Lf beta=%Lf\n", alpha, theta, beta);
ans = dl*AB*0.5L + R*PA*cost + beta*R2;
}else{
if (PA2 <= R2) ans = PI*R2;
else{
LD theta = PI*0.5L - acos(cost);
ans = 2*R*PA*cost + (PI-2*theta)*R2;
}
}
printf("%.12Lf\n", ans);
}
return 0;
}
K. 排列与质数
乍一看很简单,再一想有点难,仔细一想还是很简单的一个构造题
首先很容易想到根据\(2\)是质数这一点尽量把奇偶性相同的数放在一起,但这样交错的地方就不好处理
注意到最不好搞的两个数就是\(2,n-1\),因此我们考虑先把它们拿出来构造一个合法的解,然后再找个地方塞回去
当\(n\)为奇数时,我们可以这样构造:
当\(n\)为偶数时,我们可以这样构造:
然后注意到我们总可以把\(2\)放在\(5,7\)的中间,把\(n-1\)放在\(n-4,n-6\)的中间
但要注意这种构造方法只适用于\(n>11\)的情形,因此\(n\le 11\)的情况需要爆搜求解
#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,ans[N],cnt;
inline void BF(void)
{
RI i; for (i=1;i<=n;++i) ans[i]=i;
auto is_prime=[&](CI x)
{
if (x==2||x==3||x==5||x==7) return 1; return 0;
};
bool sign=0; do
{
bool flag=1; for (i=1;i<=n;++i)
if (!is_prime(abs(ans[i]-ans[i%n+1]))) { flag=0; break; }
if (flag) { sign=1; break; }
} while (next_permutation(ans+1,ans+n+1));
if (!sign) return (void)(puts("-1"));
for (i=1;i<=n;++i) printf("%d ",ans[i]);
}
int main()
{
//freopen("K.in","r",stdin); freopen("K.out","w",stdout);
RI i; if (scanf("%d",&n),n<=11) BF(); else
{
if (n%2==1)
{
ans[1]=1; ans[2]=3; ans[3]=5; ans[4]=2; ans[5]=7;
for (cnt=5,i=9;i<=n-6;i+=2) ans[++cnt]=i;
for (ans[++cnt]=n-1,i=n-4;i<=n;i+=2) ans[++cnt]=i;
for (i=n-3;i>=1;i-=2) ans[++cnt]=i;
} else
{
ans[1]=1; ans[2]=3; ans[3]=5; ans[4]=2; ans[5]=7;
for (cnt=5,i=9;i<=n-3;i+=2) ans[++cnt]=i;
for (i=n;i>=n-4;i-=2) ans[++cnt]=i;
for (ans[++cnt]=n-1,i=n-6;i>=1;i-=2) ans[++cnt]=i;
}
for (i=1;i<=n;++i) printf("%d ",ans[i]);
}
return 0;
}
L. 猜数游戏
好神的题,做不来一点
Postscript
下周开始就开始复习准备期末考了,除了下周末的重庆市赛外可能都没啥训练了
但如果有ECF资格的皇城PK的话再另说,现在也没下定论的说
- Programming Collegiate Provincial Contest Henanprogramming collegiate provincial contest programming collegiate provincial shandong programming provincial collegiate sichuan programming collegiate provincial guangdong programming provincial collegiate shandong programming collegiate provincial counting programming provincial collegiate sponsored 2023 programming collegiate provincial 题解programming collegiate provincial programming collegiate jiangsu contest