江西理工大学摸底测试题解
A: Water
思路:用一个数组add[i]记录第i个位置上加的总的水量,用一个sum维护当前的总水量,从前往后遍历,每次加上add[i]后于容量比较即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e5+10;
int main()
{
int T;
int n,m;
ll vc[maxx];
ll add[maxx];
cin>>T;
while(T--)
{
memset(vc,0,sizeof(vc));
memset(add,0,sizeof(add));
cin>>n>>m;
for(int a=1;a<=n;a++)cin>>vc[a];
ll i,j;
for(int a=1;a<=m;a++)
{
cin>>i>>j;
add[i]+=j;
}
ll sum=0;
for(int a=1;a<=n;a++)
{
sum+=add[a];
if(sum>=vc[a])
{
cout<<vc[a]<<" ";
sum-=vc[a];
}
else
{
cout<<sum<<" ";
sum=0;
}
}
cout<<endl;
}
return 0;
}
B: Prime Split
思路:预处理出4e4里的所有的素数,对于每一个n,枚举两个素数,判断第三个是不是素数即可(三个素数从大到小排,避免重复)。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=4e4+10;
ll prime[maxn]; //就是个素数表
bool sf[maxn];
ll num=0; //判断这个数是不是素数,sf[i]中的i是从1到maxn的数
void sushu()
{ //核心 欧拉筛代码
//num 用来记筛到第几个质数
memset(sf,true,sizeof(sf));
sf[1] = false;
sf[0] = false; //1 0 特判
for(int i = 2;i <= maxn; i ++)
{ //外层枚举1~maxn
if(sf[i]) prime[++num] = i; //如果是质数就加入素数表
for(int j = 1;j <= num;j ++)
{ //内层枚举num以内的质数
if(i * prime[j] > maxn) break; //筛完结束
sf[i * prime[j]] = false; //筛掉...
if(i % prime[j] == 0) break; //避免重复筛
}
}
}
int erfen(int x)
{
int st=0,len=num+1;
while(len-st!=1)
{
int mid=(st+len)/2;
if(prime[mid]>x)len=mid;
else st=st=mid;
}
return st;
}
int main()
{
int T;
int n;
int k,pos;
int ans=0;
sushu();
cin>>T;
while(T--)
{
cin>>n;
ans=0;
pos=erfen(n)+1;
for(int i=1;i<=pos;i++)
for(int j=i;j<=pos;j++)
{
k=n-prime[i]-prime[j];
if(k<=0||k<prime[j])continue;
else
{
if(sf[k])
ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
C: connnect
思路:只需要建立3(n-1)条边即可,x,y,z分别排序相邻的两个点建一条边,跑一边最小生成树就行。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxx=2e5+10;
struct node
{
ll from,to;
ll val;
}edge[maxx*3];
struct Node
{
ll x,y,z;
ll idex;
}poll[maxx];
bool cmp1(Node a,Node b){return a.x<b.x;}
bool cmp2(Node a,Node b){return a.y<b.y;}
bool cmp3(Node a,Node b){return a.z<b.z;}
bool cmp(node a,node b){return a.val<b.val;}
ll Father[maxx];
ll Find(ll x)
{
if(Father[x]==x)return x;
else return Father[x]=Find(Father[x]);
}
ll unite(ll x,ll y)
{
ll a=Find(x);
ll b=Find(y);
if(a!=b)
{
Father[a]=b;
return 1;
}
else return 0;
}
int main()
{
ll n;
ll d=0;
cin>>n;
for(ll a=1;a<=n;a++)Father[a]=a;
for(int a=1;a<=n;a++)
{
cin>>poll[a].x>>poll[a].y>>poll[a].z;
poll[a].idex=a;
}
sort(poll+1,poll+1+n,cmp1);
for(ll a=1;a<n;a++)
{
++d;
edge[d].from=poll[a].idex;
edge[d].to=poll[a+1].idex;
edge[d].val=abs(poll[a].x-poll[a+1].x);
}
sort(poll+1,poll+1+n,cmp2);
for(ll a=1;a<n;a++)
{
++d;
edge[d].from=poll[a].idex;
edge[d].to=poll[a+1].idex;
edge[d].val=abs(poll[a].y-poll[a+1].y);
}
sort(poll+1,poll+1+n,cmp3);
for(ll a=1;a<n;a++)
{
++d;
edge[d].from=poll[a].idex;
edge[d].to=poll[a+1].idex;
edge[d].val=abs(poll[a].z-poll[a+1].z);
}
sort(edge+1,edge+1+d,cmp);
ll ans=0,cou=0;
for(ll a=1;a<=d;a++)
{
if(unite(edge[a].from,edge[a].to))
{
ans+=edge[a].val;
cou++;
}
if(cou==n-1)break;
}
cout<<ans<<endl;
return 0;
}
D: K-nary
思路:数位dp,dp[i][j]表示有i位数,最后一位为j,dp[i][j]=求和dp[i-1][k],( abs( k ) > c )。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxx=1e3+10;
const ll MOD=1e9+7;
ll dp[maxx][maxx];
ll sum1;
ll sum2;
int n,k,c;
int main()
{
int T;
cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
sum1=sum2=0;
cin>>n>>k>>c;
k--;
ll sum=0;
int t=0;
for(int a=0;a<=k;a++)dp[1][a]=1,sum1+=dp[1][a];
for(int i=2;i<=n;i++)
{
sum=0;
if(i==n)t=1;
for(int j=t;j<=k;j++)
{
sum2=0;
for(int p=max(0,j-c);p<=min(j+c,k);p++)
sum2+=dp[i-1][p];
dp[i][j]=(sum1-sum2)%MOD;
sum+=dp[i][j];
}
sum1=sum;
}
ll ans=0;
for(int a=0;a<=k;a++)
ans=(ans+dp[n][a])%MOD;
cout<<ans<<endl;
}
return 0;
}
E: Number
思路:用dp的思想求x,dp[i]表示i可以表示最大x,dp[i]=max(dp[i],dp[j]*dp[i-j]),求出x后用欧几里得求逆元(费马小定理x要为质数)。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxx=1e5+10;
ll dp[60];
ll exgcd(ll a,ll b,ll &x,ll &y)
{
ll d=a;
if(b!=0)
{
d=exgcd(b,a%b,y,x);
y-=a/b*x;
}
else
{
x=1;
y=0;
}
return d;
}
ll inverse(ll a,ll m)
{
ll x,y;
exgcd(a,m,x,y);
return (x%m+m)%m;
}
int main()
{
int n;
cin>>n;
dp[1]=1;
dp[2]=2;
dp[3]=3;
dp[4]=4;
for(int i=5;i<=n;i++)
{
dp[i]=i;
for(int j=1;j<i;j++)
dp[i]=max(dp[i],dp[j]*dp[i-j]);
}
ll x=dp[n];
cout<<inverse(n,x)<<endl;;
return 0;
}
F: 操作数
思路:线段树的区间求和,每个点只要操作次数为奇数则为1,否则为0
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long INF=4e5+10;
typedef long long ll;
struct gg
{
int left;
int right;
long long lazy;
int getm(){return (left+right)/2;}
}tree[INF];
void pushdown(int i)
{
if(tree[i].lazy)
{
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i].lazy=0;
}
}
void builttree(int l,int r,int i)
{
tree[i].left=l;
tree[i].right=r;
tree[i].lazy=0;
if(l==r)return;
int mid=(l+r)/2;
builttree(l,mid,i<<1);
builttree(mid+1,r,i<<1|1);
}
void updatetree(int l,int r,ll c,int i)
{
int mid=tree[i].getm();
if(l<=tree[i].left&&tree[i].right<=r)
{
tree[i].lazy+=c;
return ;
}
pushdown(i);
if(mid>=l)updatetree(l,r,c,i<<1);
if(mid<r)updatetree(l,r,c,i<<1|1);
}
ll query(int idex,int i)
{
int mid=tree[i].getm();
if(tree[i].left==tree[i].right)
{
if(tree[i].lazy%2==0)return 0;
else return 1;
}
pushdown(i);
if(mid>=idex)return query(idex,i<<1);
if(mid<idex)return query(idex,i<<1|1);
}
int main()
{
int n,m;
int po,l,r,x;
cin>>n>>m;
builttree(1,n,1);
while(m--)
{
cin>>po;
if(po==1)
{
cin>>l>>r;
updatetree(l,r,1,1);
}
else
{
cin>>x;
cout<<query(x,1)<<endl;
}
}
return 0;
}
G: 聚会
思路:预处理出C几几(有除法,注意要求逆元),然后乘上2的几次方减2,累加总数即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxx=1e5+10;
const ll MOD=1e9+7;
ll mypow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)res=(res*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return res;
}
int main()
{
ll n;
ll number[maxx];
ll ans=0;
cin>>n;
number[2]=((n*(n-1))%MOD*mypow(2,MOD-2))%MOD;
for(int i=3;i<=n;i++)
number[i]=(number[i-1]*((n-i+1)*mypow(i,MOD-2)%MOD)%MOD)%MOD;
for(int i=2;i<=n;i++)
ans=(ans+(number[i]*(mypow(2,i)-2))%MOD)%MOD;
cout<<ans<<endl;
return 0;
}
H: 地图
思路:求三次bfs,第一次为第一个图,第二次为第二个图,第三位两个的合起来的图,求每次的步数,每次相等且可以到达即为YES,否则为NO。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int han[4]={0,1,0,-1};
int lie[4]={1,0,-1,0};
int mapp[510][510];
int n,m;
int step[510][510];
int bfs(char vis[510][510])
{
queue<pair<int,int> >str;
memset(mapp,0,sizeof(mapp));
str.push(make_pair(1,1));
if(mapp[1][1]==1){return -1;}
if(n==1&&m==1&&vis[n][m]!='#')return 1;
mapp[1][1]=1;
step[1][1]=1;
while(str.size())
{
pair<int,int>po=str.front();
str.pop();
for(int a=0;a<4;a++)
{
int nowh=po.first+han[a];
int nowl=po.second+lie[a];
if(nowh>=1&&nowh<=n&&nowl>=1&&nowl<=m&&mapp[nowh][nowl]==0&&vis[nowh][nowl]!='#')
{
mapp[nowh][nowl]=1;
step[nowh][nowl]=step[po.first][po.second]+1;
if(nowh==n&&nowl==m)return step[nowh][nowl];
str.push(make_pair(nowh,nowl));
}
}
}
return -1;
}
int main()
{
cin>>n>>m;
char c[3][510][510];
for(int a=1;a<=n;a++)
for(int b=1;b<=m;b++)
cin>>c[1][a][b];
for(int a=1;a<=n;a++)
for(int b=1;b<=m;b++)
cin>>c[2][a][b];
int flag=1;
int ans1=bfs(c[1]),ans2=bfs(c[2]);
if(ans1!=ans2||(ans1==ans2&&ans1==-1))flag=0;
for(int a=1;a<=n;a++)
for(int b=1;b<=m;b++)
{
if(c[1][a][b]!='#'&&c[2][a][b]=='#')
c[1][a][b]='#';
}
int ans3=bfs(c[1]);
if(ans1!=ans3)flag=0;
/*cout<<ans1<<" "<<ans2<<" "<<ans3<<endl;*/
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
I: 我是签到题
思路:从前往后遍历到(n-1)/2,遇到ai!=a n-i-1都改成最小的那个。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=2e5+10;
int main()
{
string s;
cin>>s;
int n=s.length();
for(int a=0;a<=(s.length()-1)/2;a++)
{
if(s[a]!=s[n-a-1])
{
if(s[a]<s[n-a-1])s[n-a-1]=s[a];
else s[a]=s[n-a-1];
}
}
cout<<s<<endl;
return 0;
}