牛客寒假训练赛1,自己水平还是太差了。
A:
题意:有计算符号和结果,求最初的数
思路:简单模拟
#include<cstdio>
#define ll long long
struct note
{
int opt;
ll num;
}a[101];
int main()
{
int n;
ll k;
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d%lld",&a[i].opt,&a[i].num);
for(int i=n;i>=1;i--)
{
switch(a[i].opt)
{
case 1:k-=a[i].num;break;
case 2:k+=a[i].num;break;
case 3:k/=a[i].num;break;
case 4:k*=a[i].num;break;
}
}
printf("%lld",k);
return 0;
}
B:给定2,0,4的数量,对其进行排列,计算1~i的(a[i]-a[i-1])^2的和
构造,4,0,4,0是最优解,所以需要先排列,然后再考虑其他情况
#include<cstdio>
int a[5];
int main()
{
int n;
int ans=0;
int p=0;
int num;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
a[num]++;
}
for(int i=1;i<=n;i++)
{
switch(p)
{
case 0:
{
if(a[4])
{
ans+=16;
a[4]--;
p=4;
}
else
if(a[2])
{
ans+=4;
a[2]--;
p=2;
}
break;
}
case 2:
{
if(a[4])
{
ans+=4;
a[4]--;
p=4;
}
else
if(a[0])
{
ans+=4;
a[0]--;
p=0;
}
break;
}
case 4:
{
if(a[0])
{
ans+=16;
a[0]--;
p=0;
}
else if(a[2])
{
ans+=4;
a[2]--;
p=2;
}
break;
}
}
}
printf("%d",ans);
return 0;
}
C:
题意:n个节点,第i个节点有pi,当pi>pj时,飞船可以从i到j,飞往后,耐久变为t异或pj,t的初始值为1,求到达n的耐久最大为多少
思路:dp,实际上有点floyd的感觉,又有点搜索的感觉(确实可以拿搜索过
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 10003
#define MAXP 4096
//3000用二进制表示最大也就是1<<12
//less,greater包含在iostream里面??挠头.jpg
using namespace std;
int n;
int p[MAXN];
int dp[MAXP];
int main()
{
int max=-1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
int begin=p[1],x=1,y=n,end=p[n];
if(n==1)//排除n==1的特殊情况
{
printf("%d",p[1]?p[1]:-1);
return 0;
}
if(begin<=end)//只有在这种情况下才无法到达
{
printf("-1");
return 0;
}
sort(p+1,p+1+n,greater<int>());
while(p[x]>begin&&x<n)
x++;
while(p[y]<end&&y>1)
y--;
dp[end^begin]=1;
for(int i=x+1;i<y;i++)
{
for(int j=MAXP-1;j>=0;j--)
dp[j]|=dp[j^p[i]];//需要保证之前的情况也能够到达
}
for(int i=MAXP-1;i>=0;i--)
if(dp[i]) //找到最大值
{
printf("%d",i);
return 0;
}
return 0;
}
D:
题意:初始黄金数分别为A,B,两人从两端相向而行,当位置和n互质的时候,A*k^x,B*k^y,求最后两者之和,并向1e9+7取模
思路:数论,求出与n互质的数的和,然后快速幂(或者其他操作
#include<cstdio>
#define mod 1000000007
#define ll long long
//relocation truncated to fit 内存使用超限
//欧拉函数
//此处应该使用求单个数欧拉函数的函数
//因为根本不需要求全部
int phi(int x){
int ans = x;
for(int i = 2; i*i <= x; i++){
if(x % i == 0){
ans = ans / i * (i-1);
while(x % i == 0) x /= i;
}
}
if(x > 1) ans = ans / x * (x-1);
//若x有大于根号下x的因数,则需继续删去
//易得,x只有可能又一个这样的因数
//所以判断一次即可
return ans;
}
//快速幂
//有时间可以学下位运算的写法
ll qik(ll a,ll x)
{
ll res=1;
while(x)
{
if(x%2!=0)
res=(res*a)%mod;
a=(a*a)%mod;
x/=2;
}
return res;
}
int main()
{
ll n,k,a,b;
scanf("%ld%ld%ld%ld",&n,&k,&a,&b);
ll x=phi(n)*n/2;
printf("%ld",1ll*(qik(k,x)*(a+b))%mod);
return 0;
}
E:
题意:n*m的矩阵,p个轰炸机,两种轰炸模式,一种是对角线分别为x,y的菱形,一种只轰炸上半部分,求最后轰炸次数的异或和
思路:查分,但是暂时还是看不懂几个数组之间是怎么实现的(我理解能力真差.jpg)
F:
题意:长度为n的序列,数字在1~V之间,给任意位置的数赋值形成子序列,子序列需满足严格递增,萌值定义为除序列最大值以外所有值的乘积,若只有一个数则为1,求所有序列萌值的和
思路:dp,自己尝试着去写状态转移方程,并且利用sum作为前缀和,记录前面的代价
#include<cstdio>
#define MAXN 5005
#define ll long long
#define mod 1000000007
#define MAXN 5005
int dp[MAXN][MAXN];
int main()
{
int n,v;
scanf("%d%d",&n,&v);
for(int i=1;i<=v;i++)
dp[1][i]=1;
for(int i=2;i<=n;i++)
{
ll sum=1;
//类似前缀和
//用sum来表示长度小于自己的合法子序列
//因为明显每次增加最后一个数之后,最大的数就不是之前的数
//然后就需要被乘增加入萌值
for(int j=1;j<=v;j++)
{
dp[i][j]=(dp[i-1][j]+sum)%mod;
sum=(sum+dp[i-1][j]*j)%mod;
}
}
ll ans=0;
for(int i=1;i<=v;i++)
ans=(ans+dp[n][i])%mod;
printf("%lld",ans);
return 0;
}
G:
题意:排序后所有数左右相差值为1,则说明这个序列为“萌”的,现在给出序列n,求最小长度[l,r]的萌序列,并且要求含有x,y
H: