unfinished
华东理工大学 2026 年程序设计竞赛春季校赛(重现赛)总结
比赛链接,题解和题目链接,队友:rabbit_mygo。
I
简单题,分别计算两种作物的利润即可。
code:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <queue>
#define FOR(i,a,b) for(int i = (a);i <= (b);++i)
#define REP(i,a,b) for(int i = (a);i >= (b);--i)
#define ll long long
static char stkk[200];
template<typename T>inline void output(T x){
if(!x)return putchar('0'),void();
if(x<0)x = ~x+1,putchar('-');
int top = 0;
for(;x;stkk[++top]=x%10^48,x/=10);
for(;top;putchar(stkk[top--]));
}
template<typename T>inline void readx(T &x){
x = 0;int y = 1;char c = getchar();
for(;c<48||c>58;c = getchar())if(c=='-')y = -1;
for(;c>=48&&c<=58;c = getchar())x = (x<<1)+(x<<3)+(c^48);
x *= y;
}
const int N = 1e5+10;
static int n,m,k;
inline ll cal0(int p,int q,int t){
return 1ll*(k-1)/t*(q-p);
}
inline ll cal1(int p,int q,int t,int s){
return k>=t?1ll*((k-t-1)/s+1)*q-p:0;
}
inline void ckmax(ll &x,ll y){
x<y&&(x=y);
}
inline void solve(){
readx(n),readx(m),readx(k);
ll ans = 0;
int p,q,t,s;
FOR(i,1,n)readx(p),readx(q),readx(t),ckmax(ans,cal0(p,q,t));
FOR(i,1,m)readx(p),readx(q),readx(t),readx(s),ckmax(ans,cal1(p,q,t,s));
output(ans),putchar(10);
}
signed main(){
int T;
for(readx(T);T--;solve());
return 0;
}
F
简单题,分成四个象限求答案即可。
code:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <queue>
#define FOR(i,a,b) for(int i = (a);i <= (b);++i)
#define REP(i,a,b) for(int i = (a);i >= (b);--i)
#define ll long long
static char stkk[200];
template<typename T>inline void output(T x){
if(!x)return putchar('0'),void();
if(x<0)x = ~x+1,putchar('-');
int top = 0;
for(;x;stkk[++top]=x%10^48,x/=10);
for(;top;putchar(stkk[top--]));
}
template<typename T>inline void readx(T &x){
x = 0;int y = 1;char c = getchar();
for(;c<48||c>58;c = getchar())if(c=='-')y = -1;
for(;c>=48&&c<=58;c = getchar())x = (x<<1)+(x<<3)+(c^48);
x *= y;
}
inline int cal1(int x,int y,int tx,int ty){
if(ty>=y&&tx>x)return 0;
if(ty<y&&tx>=x)return 1;
if(ty<=y&&tx<x)return 2;
if(ty>y&&tx<=x)return 3;
}
inline int cal0(int x,int y,int tx,int ty){
return x==tx?ty>y?3:1:tx<x?2:0;
}
inline int cal(int p0,int p1){
return p1>=p0?p1-p0:p1-p0+4;
}
inline void get_c(char &c){
for(c = getchar();std::isspace(c);c = getchar());
}
inline void solve(){
int x,y,tx,ty;char c;
readx(x),readx(y),get_c(c),readx(tx),readx(ty);
int p1;
int p0 = c=='E'?0:c=='S'?1:c=='W'?2:3;
if(x==tx&&y==ty)output(0),putchar(10);
else if(x==tx||y==ty){
p1 = cal0(x,y,tx,ty);
output(cal(p0,p1)),putchar(10);
}
else {
// printf("p0:%d p1:%d\n",p0,p1);
p1 = cal1(x,y,tx,ty);
if(p0==0){
if(p1==0)output(3);
else if(p1==1)output(1);
else if(p1==2)output(2);
else output(3);
}
else if(p0==1){
if(p1==0)output(3);
else if(p1==1)output(3);
else if(p1==2)output(1);
else output(2);
}
else if(p0==2){
if(p1==0)output(2);
else if(p1==1)output(3);
else if(p1==2)output(3);
else output(1);
}
else{
if(p1==0)output(1);
else if(p1==1)output(2);
else if(p1==2)output(3);
else output(3);
}
putchar(10);
}
}
signed main(){
int T;for(readx(T);T--;solve());
return 0;
}
G
挺好玩的题。
首先注意到胜者可以写成 \(1+n+km\) 的形式,于是我们做差就可以得到 \(m\) 的倍数。
我们定义胜者为 \(w_i\),而败者为 \(l_i\),于是有 \(km=\gcd_{1\le x<y\le k}(w_x-w_y)\)。现在我们证明 \(m=km\) 是一定不劣的,因为没啥能缩小 \(m\) 范围的方式了。
- 可以发现加时情况下比分差会落在 \([2,m+1]\) 之间,那 \(m\) 尽可能取大是不劣的。
此时钦定所有胜者中比分最小 \(w_{、min}\) 的没有进行加时,而其他进行加时同样是优的:
- 我们可以取 \(n=w_{\min}-1\),这样题目里所有的情况都满足了。
这样所有败者都是尽可能成立的了。
所以现在有 \(n=w_{\min}-1, m=\gcd_{1\le x<y\le k}(w_x-w_y)\),现在我们有一个结论:\(\forall i \in [1,n],\ j \in [1,n]\ \gcd\{p_i - p_j\}\) 与 \(\forall i \in [1,n-1]\ \gcd\{p_{i+1} - p_i\}\) 相等。具体怎么来的不证。
然后 \(m,n\) 就都能求了。最后判断方式为:
然后就做完了。
code:
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define pii pair<int,int>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=5e5+10;
int n,m,k,T;
pii a[N];
vector<int> g[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
int tg=0,mn=LONG_LONG_MAX;
cin>>k;
rep(i,1,k){
cin>>a[i].fi>>a[i].se;
mn=min(mn,max(a[i].fi,a[i].se));
}if(k==1) cout<<"YES\n";
else{
m=abs(max(a[1].fi,a[1].se)-max(a[2].fi,a[2].se));
rep(i,2,k-1){
m=__gcd(m,abs(max(a[i].fi,a[i].se)-max(a[i+1].fi,a[i+1].se)));
}n=mn-1;
if(m!=0){
rep(i,1,k){
int tp=max(a[i].fi,a[i].se);
if(mn==tp){
if(abs(a[i].fi-a[i].se)>n+1) tg=1;
}else{
if(abs(a[i].fi-a[i].se)>m+1) tg=1;
}
}
}
if(tg==1) cout<<"NO\n";
else cout<<"YES\n";
}
}
return 0;
}
D
简单构造。
发现应该是 \(\frac {n}{\log n}\) 的询问,然后注意一下横向的边是比较特别的,因为这种边只能是单向的,而且两岸的边一定是反向的,也就是说如果要从这个边的左侧走到右侧,一定会经过这两条边固定向右的那条。
考虑用二进制赋值,我们把横向的边 \(29\) 个位一组,把一组中的所有在一侧的横向边标记权值,然后其他边为 \(0\) 就好了。
code:
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=5e5+10;
int n,m,k,T,a[N];
vector<int> g[N];
int ksm(int x,int k){
int ans=1;
while(k){
if(k%2) ans=ans*x;
x=x*x;k/=2;
}return ans;
}
signed main(){
cin>>n;
rep(i,1,n-1){
cout<<ksm(2,(i-1)%29)<<" "<<0<<" "<<0<<" "<<0<<'\n';
fflush(stdout);
}rep(i,1,(n+28)/29){
cout<<"? N "<<(i-1)*29+1<<" S "<<min(n,i*29+1)<<'\n';
fflush(stdout);
int x;cin>>x;
rep(j,1,29){
int tp=x%2;x/=2;
if(tp==0) a[j+(i-1)*29]=1;
}
}cout<<"! ";
fflush(stdout);
rep(i,1,n-1){
if(a[i]==0) cout<<"O";
else cout<<"I";
fflush(stdout);
}fflush(stdout);
return 0;
}
H
计数题。
首先发现置换其实可以看成连边,然后这样会构成很多个环,具体为什么可以看这个视频:link。然后我们发现交换两个数其实就是换两条边,而且答案其实就是这些换的 \(\text{lcm}\)。于是我们分类讨论一下。
- 环内两数交换,会导致换分裂,但是所有环内的两个值,如果相隔一样的距离,那么交换后的结果都是一样的。所以可以发现总共本质只有 \(O(n)\) 种答案。
- 环外两数交换,会导致两环结合,但是总共只有 \(n\) 个点,所以总共也只有 \(O(\sqrt n)\) 种环长,所以暴力组合也只有 \(O(n)\) 种可能。
最后处理一下 \(\text{lcm}\)。就是用一些桶存下每个素数的最大值,然后要判断的时候用栈回溯和暴力拆分数字就好了,比较难写。
code:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#define FOR(i,a,b) for(int i = (a);i <= (b);++i)
#define REP(i,a,b) for(int i = (a);i >= (b);--i)
#define ve std::vector
#define pb push_back
#define ll long long
#define int long long
static char stkk[200];
template<typename T>inline void output(T x){
if(!x)return putchar('0'),void();
if(x<0)x = ~x+1,putchar('-');
int top = 0;
for(;x;stkk[++top]=x%10^48,x/=10);
for(;top;putchar(stkk[top--]));
}
template<typename T>inline void readx(T &x){
x = 0;int y = 1;char c = getchar();
for(;c<48||c>58;c = getchar())if(c=='-')y = -1;
for(;c>=48&&c<=58;c = getchar())x = (x<<1)+(x<<3)+(c^48);
x *= y;
}
const int N = 1e5+10,mo = 998244353;
static int n,a[N];
struct node{
int blp,v;
};
static ve<node> p[N];
inline void init_fac(int x,ve<node> &p){
for(int i = 2;i*i <= x;++i){
if(!(x%i)){
int v = 1;
for(;!(x%i);x/=i,v*=i);
p.pb((node){i,v});
}
}
if(x!=1){
p.pb((node){x,x});
}
}
inline int ksm(int a,int b){
int c = 1;for(;b;b>>=1,a = 1ll*a*a%mo)if(b&1)c = 1ll*c*a%mo;return c;
}
static int inv[N];
inline void init(int n){
//p,inv
FOR(i,1,n)init_fac(i,p[i]);
inv[0] = 1;
FOR(i,1,n)inv[i] = ksm(i,mo-2);
inv[0] = 1;
}
static int f[N],sz[N];
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
inline void merge(int x,int y){
// printf("x:%d y:%d\n",x,y);
if((x=find(x))==(y=find(y)))return;
f[y] = x,sz[x]+=sz[y];
}
struct node1{
int v;
bool operator<(const node1& A)const{
return v>A.v;
}
};
static std::multiset<node1> s[N];
static int ans;
inline void del_s(int l){
if(!s[l].empty()){
int x = (*s[l].begin()).v;
ans = 1ll*ans*inv[x]%mo;
}
}
inline void add_s(int l){
if(!s[l].empty()){
int x = (*s[l].begin()).v;
ans = 1ll*ans*x%mo;
}
}
inline void ad_v(int x){
for(auto &t:p[x]){
del_s(t.blp);
s[t.blp].insert((node1){t.v});
add_s(t.blp);
}
}
inline void dl_v(int x){
for(auto &t:p[x]){
del_s(t.blp);
auto tmp = s[t.blp].find((node1){t.v});
// if(tmp==s[t.blp].end())puts("Err"),exit(0);
s[t.blp].erase(s[t.blp].find((node1){t.v}));
add_s(t.blp);
}
}
static int ct[N],xx[N],tp;
inline void solve(){
//init f,tp,ct,s
FOR(i,1,n)
tp = 0;FOR(i,1,n)ct[i] = 0;
FOR(i,1,n)s[i].clear();
//rd
readx(n);
FOR(i,1,n)f[i] = i,sz[i] = 1;;
// FOR(i,1,n)printf("i:%d find:%d\n",i,find(i));
FOR(i,1,n)readx(a[i]),merge(i,a[i]);
// FOR(i,1,n)printf("i:%d find:%d\n",i,find(i));
// //merge,get ct
FOR(i,1,n)if(i==find(i)){
// printf("i:%d sz:%d\n",i,sz[i]);
++ct[sz[i]],xx[++tp] = sz[i];
}
//pre ans
ans = 1;
FOR(i,1,n)if(ct[i]){
FOR(j,1,ct[i])ad_v(i);
}
int fnl = 0;
//get in
FOR(i,1,n)if(ct[i]){
dl_v(i);
FOR(x,1,i-1){
ad_v(x),ad_v(i-x);
// printf("i:%d ct:%d ans:%d\n",i,ct[i],ans);
fnl = (0ll+fnl+1ll*i*ct[i]%mo*ans)%mo;
dl_v(x),dl_v(i-x);
}
ad_v(i);
}
//get xx,get ou
std::sort(xx+1,xx+1+tp);tp = std::unique(xx+1,xx+1+tp)-xx-1;
FOR(i,1,tp){
FOR(j,1,tp){
if(i==j&&ct[xx[i]]<=1)continue;
dl_v(xx[i]),dl_v(xx[j]);
ad_v(xx[i]+xx[j]);
fnl = (0ll+fnl+1ll*ct[xx[i]]*xx[i]%mo
*(ct[xx[j]]-(i==j))%mo*xx[j]%mo*ans%mo)%mo;
dl_v(xx[i]+xx[j]);
ad_v(xx[i]),ad_v(xx[j]);
}
}
fnl = 1ll*fnl*ksm(2,mo-2)%mo;
output((0ll+fnl+mo)%mo),putchar(10);
}
signed main(){
//init
init(N-5);
//solve
int T;for(readx(T);T--;solve());
return 0;
}

浙公网安备 33010602011771号