第十届“图灵杯”NEUQ-ACM程序设计竞赛个人赛 题解
A .有用的算法
题意:
给你一个数组,要你判断是否是单调不降,或者单调不升的
做法:
直接模拟判断即可
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
void solve(){
int n;
cin>>n;
vector<int>a(n),s1(n),s2(n);
for(int i=0;i<n;i++){
cin>>a[i];
s1[i]=s2[i]=a[i];
}
sort(s1.begin(),s1.end());
sort(s2.begin(),s2.end(),greater<int>());
if(a==s1||a==s2){
cout<<"erfen is useful!\n";
}else{
cout<<"bukeyi\n";
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
B 平衡数
题意:
给你一个四位数,问你前两位的数位和与后两位的数位和相不相等
做法:
模拟判断
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
void solve(){
string s;
cin>>s;
int a=(s[0]-'0')+(s[1]-'0');
int b=(s[2]-'0')+(s[3]-'0');
cout<<(a==b?"YES\n":"NO\n");
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
//t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
C 三角形
题意:
给你三个点:
问点
做法:
分情况讨论:
-
若
,这种情况 点一定落在 点右侧或者与其重合,或者落在 点上侧或与其重合,这种情况一定是在外部 -
否则我们讨论:
的情况当
一定是在三角形内部然后我们发现我们就可以把三角形分成两块区域:
,我们可以利用相似三角形成对应边比例判断点
是否落在直线 或者直线 的下方即可
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
void solve(){
int xb,xc,yc;
cin>>xb>>xc>>yc;
int xp,yp;
cin>>xp>>yp;
if(xp<xb&&yp<yc){
if(xp==xc)cout<<"yes\n";
else if(xp<xc){
if(yp*xc<xp*yc)cout<<"yes\n";
else cout<<"no\n";
}else{
if(yp*(xb-xc)<yc*(xb-xp))cout<<"yes\n";
else cout<<"no\n";
}
}else{
cout<<"no\n";
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
D 文稿修订
题意:
给你一堆字符串,要你把其中的
同时你需要统计字符串中所有非全是大写的
做法:
字符串模拟,
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
void solve(){
vector<string>ans;
string s;
int cnt=0;
while(getline(cin,s),s!="#"){
stringstream ssin(s);
string ss,res;
while(ssin>>ss){
if(ss=="NEUQ"){
if(res.size())res+=" ";
res+="WOW NEUQ";
}else{
if(res.size())res+=" ";
res+=ss;
if(ss.size()==4){
bool ok=false;
for(auto &c:ss){
if(c>='a'&&c<='z')ok=true;
if(c>='A'&&c<='Z')c+=32;
}
if(ss=="neuq"&&ok)cnt++;
}
}
}
ans.push_back(res);
}
cout<<cnt<<'\n';
for(auto s:ans){
cout<<s<<'\n';
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
E 减肥计划
题意:
给你
问你
做法:
发现
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
struct node{
int x,y,z,w;
}bag[20];
void solve(){
int n,a,b,c;
cin>>n>>a>>b>>c;
for(int i=0;i<n;i++){
auto &[x,y,z,w]=bag[i];
cin>>x>>y>>z>>w;
}
int ans=0;
for(int i=0;i<1<<n;i++){
int sa=0,sb=0,sc=0,res=0;
for(int j=0;j<n;j++){
if(i>>j&1){
auto [x,y,z,w]=bag[j];
sa+=x,sb+=y,sc+=z,res+=w;
}
}
if(sa<=a&&sb<=b&&sc<=c){
ans=max(ans,res);
}
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
F 吃包子
题意:
你有
问你在这种情况下,最多能吃到多少肉包子
做法:
双指针经典题,定义
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=1e6+10;
int a[N];
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
//two point
int ans=0;
for(int i=1,j=1,sum=0;i<=n;i++){
sum+=a[i]==0;
while(sum>m){
sum-=a[j++]==0;
}
ans=max(ans,i-j+1-sum);
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
G 数字鉴定
题意:
给你
做法:
观察区间范围
然后差分做完求一遍前缀和得到数组
然后我们只要利用
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
typedef pair<int,int>PII;
const int N=1e6+10;
int b[N]; //差分
bool ok[N];
void solve(){
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++){
int l,r;
cin>>l>>r;
b[l]++,b[r+1]--;
}
for(int i=1;i<N;i++){
b[i]+=b[i-1];
}
for(int i=1;i<N;i++){
for(int j=i;j<N;j+=i){
if(b[j])ok[i]=true;
}
}
while(q--){
int x;
cin>>x;
cout<<(!ok[x]?"YES\n":"NO\n");
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
H 线性变换
题意:
给你
同时你有一个加密值
你需要进行
做法:
首先我们发现
我们不可能暴力求解,但我们发现这是一个经典的式子:
由于
所以我们可以暴力循环找到这个循环节:
这里给出查找类似上述式子循环节的方法:
const int N=1e6+10;
int vis[N],tp;
int P;
while(!vis[N]){
vis[P]=++tp;
P=(P*K+B)%n;
}
我们用一个类似时间戳的想法来找到这一段循环节,我们可以举一个例子:
我们发现循环节为:
由于我们是记录时间戳,当我们发现
循环节长度就为:
故回到这个题,我们只需要找到循环节,然后我们假设循环节出现的位置是:
我们就可以知道在
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=1e6+10;
int a[N];
int vis[N]; //找循环节
int v[N]; //记一下对应时间的p
void solve(){
int n,P,K,B;
LL T;
cin>>n>>P>>K>>B>>T;
for(int i=0;i<n;i++){
cin>>a[i];
}
LL val=0,tp=0;
while(!vis[P]){
vis[P]=++tp;
val+=a[P];
v[tp]=P;
if(T==tp){
cout<<val<<'\n';
return ;
}
P=(1LL*P*K+B)%n;
}
LL res=0;
int l=vis[P],r=tp;
for(int i=1;i<l;i++){
res+=a[v[i]];
}
val-=res;
T-=l-1;
LL ans=res+val*(T/(r-l+1));
T%=(r-l+1);
for(int i=1;i<=T;i++){
ans+=a[v[l+i-1]];
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
I 试题排版
题意:
给你一个整数
做法:
完全背包裸体,凑体积恰好为
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=5100;
const int mod=998244353;
int f[N];
void solve(){
int m;
cin>>m;
f[0]=1;
for(int i=1;i<=m;i++){
for(int j=i;j<=m;j++){
f[j]+=f[j-i];
f[j]%=mod;
}
}
cout<<f[m]<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
J QQ群
题意:
你有
- 若点
在一个环(自环也算)内,则它是一个怨种 - 编号为
的点一开始就是怨种
现在你可以连一条从
请问图中怨种数量最多是多少?
做法:
由于是有向图,且涉及环,我们可以考虑用
若
若
现在我们缩完点之后,图就成了拓扑图,我们只需要在图上找一条最长链(使得链上的孤立点最多)即可
注意我们每一个强连通分量是孤立点当且仅当,它的
所以我们只要在图上
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=1e4+10;
vector<int>g[N],G[N];
int dfn[N],low[N],stk[N],id[N],sz[N];
bool cire[N];
int top,scc,tis;
bool is_stk[N];
int f[N];
bool me[N]; //自环
void tarjan(int u){
dfn[u]=low[u]=++tis;
stk[++top]=u,is_stk[u]=true;
for(auto v:g[u]){
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(is_stk[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
int y;
scc++;
do{
y=stk[top--];
is_stk[y]=false;
id[y]=scc;
cire[y]|=me[y];
sz[scc]++;
}while(y!=u);
}
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
g[i].push_back(x);
if(i==x)me[i]=true;
}
for(int i=0;i<=n;i++){
if(!dfn[i])tarjan(i);
}
for(int i=0;i<=n;i++){
for(auto j:g[i]){
if(id[j]!=id[i]){
G[id[i]].push_back(id[j]);
}
}
}
memset(f,-1,sizeof f);
for(int i=scc;i>=1;i--){
if(f[i]==-1)f[i]=sz[i]==1&&!cire[i]==1?1:0;
for(auto j:G[i]){
f[j]=max(f[j],f[i]+(sz[j]==1&&!cire[j]&&j!=1?1:0));
}
}
int ans=0,res=0;
for(int i=1;i<=scc;i++){
if(i!=1&&(sz[i]>1||sz[i]==1&&cire[i]))ans+=sz[i];
res=max(res,f[i]);
}
//cout<<ans<<' '<<res<<endl;
cout<<ans+res+1<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
K 跳跃
题意:
给你一个数轴有
你会跳到
做法:
期望
这样我们就可以定义:
则:
然后我们只要倒推,很容易得到状态转移:
我们发现
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=2e5+10;
const int mod=998244353;
int dp[N]; //表示从i跳到n+1的总金币期望
int a[N],l[N],r[N];
int suf[N]; //后缀和
int MOD(int x){
return (x%mod+mod)%mod;
}
LL qsm(LL a,LL b){
LL res=1;
while(b){
if(b&1)res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>l[i];
}
for(int i=1;i<=n;i++){
cin>>r[i];
}
for(int i=n;i>=1;i--){
LL inv=qsm(r[i]-l[i]+1,mod-2);
dp[i]=MOD(suf[min(n+1,i+l[i])]-suf[min(n+1,i+r[i]+1)])*inv%mod;
dp[i]=(dp[i]+a[i])%mod;
suf[i]=(suf[i+1]+dp[i])%mod;
}
cout<<dp[1]<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
L 我把你背回来的
题意:
给你两张一模一样的图,都有
现在你需要重新给图定义边权,规则如下:
- 对于两个图分别来说边
若从 到 的最短路都经过这条边,则新图边权为 - 若只有一个图满足,则边权为
- 若两个图都不满足,则边权
然后问你在新图中从
做法:
首先由于是无向图,我们可以求一遍从
对于某条边
然后建完图,跑一次
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
typedef pair<int,int>PII;
const int N=4e5+10;
const int INF=0x3f3f3f3f;
vector<PII>g1[N],g2[N],g3[N];
int d1[N],d2[N],d3[N];
bool st[N];
struct node{
int a,b,r,d;
}edge[N];
void dijstla(int s,int d[],vector<PII>g[],int sz){
for(int i=1;i<=sz;i++){
st[i]=false,d[i]=INF;
}
d[s]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,s});
while(heap.size()){
auto [_,u]=heap.top();
heap.pop();
if(st[u])continue;
st[u]=true;
for(auto [v,w]:g[u]){
if(d[v]>d[u]+w){
d[v]=d[u]+w;
heap.push({d[v],v});
}
}
}
}
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
auto &[a,b,r,d]=edge[i];
cin>>a>>b>>r>>d;
g1[a].push_back({b,r});
g1[b].push_back({a,r});
g2[a].push_back({b,d});
g2[b].push_back({a,d});
}
dijstla(n,d1,g1,n);
dijstla(n,d2,g2,n);
for(int i=1;i<=m;i++){
auto [a,b,r,d]=edge[i];
if(d1[b]==d1[a]+r&&d2[b]==d2[a]+d){
g3[b].push_back({a,0});
}else if(d1[b]==d1[a]+r){
g3[b].push_back({a,1});
}else if(d2[b]==d2[a]+d){
g3[b].push_back({a,1});
}else{
g3[b].push_back({a,2});
}
swap(a,b);
if(d1[b]==d1[a]+r&&d2[b]==d2[a]+d){
g3[b].push_back({a,0});
}else if(d1[b]==d1[a]+r){
g3[b].push_back({a,1});
}else if(d2[b]==d2[a]+d){
g3[b].push_back({a,1});
}else{
g3[b].push_back({a,2});
}
}
dijstla(1,d3,g3,n);
cout<<d3[n]<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
M 粉色头发的可爱女孩
题意:
有
现在有
做法:
首先抽象题意,需要我们找到同时满足拥有
我们可以考虑状态压缩
首先我们来举一个例子,比如我们现在需要更新
即对于满足
故我们发现它本质是一个递推问题,类似状态压缩
故我们只要从大到小递推即可:
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
typedef pair<int,int>PII;
const int N=21;
int f[1<<N],id[1<<N];
void solve(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
int x,m;
cin>>x>>m;
int state=0;
for(int j=0;j<m;j++){
int p;
cin>>p;
p--;
state|=1<<p;
}
if(f[state]<x){
f[state]=x;
id[state]=i;
}
}
//倒推
for(int i=(1<<k)-1;i>=1;i--){
for(int j=0;j<k;j++){
if(i>>j&1){
int s=i^(1<<j);
if(f[s]<f[i]){
f[s]=f[i];
id[s]=id[i];
}
}
}
}
int q;
cin>>q;
while(q--){
int x;
cin>>x;
int state=0;
for(int i=1;i<=x;i++){
int p;
cin>>p;
p--;
state|=1<<p;
}
if(!id[state]){
cout<<"OMG!\n";
}else{
cout<<id[state]<<"\n";
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(10);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!