A-做游戏
题目要求及数据:
签到题没什么说的
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c,x,y,z,m,n,p;
int main()
{
cin>>a>>b>>c;
cin>>x>>y>>z;
m=min(a,y);
n=min(b,z);
p=min(c,x);
m+=n+p;
cout<<m<<endl;
}
B-排数字
题目要求与数据:
解法:一开始想着找‘6’和‘1‘的顺序然后循环减来着,结果老是错,我忽略了一种情况61616这种的算有两个串,由于可以随意换子串的位置,所以开个数组往上面放记录一下即可
#include<bits/stdc++.h>
#include<string>
using namespace std;
int main()
{
char s[200010];
int x=0,y=0,z,sum=0,index=0,a[200010]={0};
cin>>z;
scanf("%s",s);
for(int i=0;i<z;i++)
{
if(s[i]=='1')
x++;
if(s[i]=='6')
y++;
}
if(x<1||y<2)
{
sum=0;
}
else
{
a[0]=6;
y--;
for(int i=1;i<z;i++)
{
if(x>=1&&y>=1)
{
if(a[i-1]=6)
{
a[i]=1;
x--;
}
if(a[i-1]=1)
{
a[i]=6;
y--;
sum++;
}
}
else
break;
}
}
cout<<sum<<endl;
}
C-求概率(还不大会)
题目数据及要求:
解法:看的一个大佬的解法附上链接:题解链接
因为任何分数都可以表示成分母为一的形式所以这里让b=1,所以当然a可以为小数,然后用dp做就很简单了,但算出来的结果要再取余不然有的数据太大过不了
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e9+7;
typedef long long ll ;
ll dp[2010][2010],p[2010],n;
int main()
{
cin>>n;
for(ll i=1;i<=n;i++)
{
scanf("%lld",&p[i]);
}
dp[0][0]=1;//0个题对0道概率肯定为1
for(int i=1;i<=n;i++)
{
dp[i][0]=dp[i-1][0]*(maxn+1-p[i])%maxn;//边界
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
dp[i][j]=(dp[i-1][j]*(maxn+1-p[i])%maxn+dp[i-1][j-1]*p[i]%maxn)%maxn;//这里最后要再取余maxn一次不然过不了数据,可能数据太大
}
}
for(int i=0;i<=n;i++)
{
printf("%lld ",dp[n][i]);
}
}
D-数三角形
题目要求及数据:
解法:按要求枚举即可,有一点要注意的是,如果三点共线的话有可能求出的边也满足钝角的要求
代码:
#include<bits/stdc++.h>
using namespace std;
struct f{
int x;
int y;
}w[510];
int main()
{ int o,sum=0;
double a, b, c, m,n,q,a1,b1,c1;
cin>>o;
for(int i=1;i<=o;i++)
{
scanf("%d%d",&w[i].x,&w[i].y);
}
for(int i=1;i<=o;i++)
{
for(int j=i+1;j<=o;j++)
{
for(int k=j+1;k<=o;k++)
{
a = (w[k].x - w[j].x)*(w[k].x - w[j].x) + (w[k].y - w[j].y)*(w[k].y - w[j].y);
m = sqrt(a);
b = (w[k].x - w[i].x)*(w[k].x - w[i].x) + (w[k].y - w[i].y)*(w[k].y - w[i].y);
n = sqrt(b);
c = (w[j].x - w[i].x)*(w[j].x - w[i].x) + (w[j].y - w[i].y)*(w[j].y - w[i].y);
q = sqrt(c);
a1=(w[k].y-w[j].y)*1.0/(w[k].x-w[j].x);
b1=(w[k].y-w[i].y)*1.0/(w[k].x-w[i].x);
if (m + n > q&&n + q > m&&m + q > n)
{
if(a+b<c||a+c<b||b+c<a)
{ if(a1!=b1)//三点共线也会有可能满足上述情况
sum++;
}
}
}
}
}
cout<<sum<<endl;
}
E-做计数
题目要求与数据:
解法:一开始胡乱做的,虽然注意到了ij<=n的要求,但也没想到怎么用,经过这次比赛提醒了我要耐心琢磨题目条件再做题
附上赛后大佬的解法:
可见只有当ij凑出的式子为完全平方式才会有一个整数k存在使k成立,又因为i*j<=n所以利用i从1到sqrt(n)来枚举平方数,因为是通过i平方出的式子所以它的因数必有i,通过上面的推导,如果它的因数还有j,那么就会存在一个k从而等式成立,还要注意的是可以i,j换位置如1 4 9,4 1 9算两个不同的式子,当i=j时只有一个式子
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e7+10;
typedef long long ll ;
int main()
{
ll n,i,j,sum=0;
cin>>n;
for(i=1;i<=sqrt(n);i++)
{
ll k=i*i;
for(j=1;j<=i;j++)
{
if(k%j==0)
{
if(i==j)
sum++;
else
sum+=2;
}
}
}
cout<<sum<<endl;
}
F-拿物品
题目要求及相关数据:
解法:这个题一开始理解错了,以为先取的人取a大的值,后取的人取i大的值就行,其实不是的,先取人取一件物品获得了a的同时,后取的人也损失了bi即此时他们的差值多了a+b,所以一贪心,就是取a+b大的。
注意:在结构体里重载运算符之后,本题还得再写一句sort来让它排序,不然不会排序
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll ;
ll n,q[maxn]={0},w[maxn]={0},p=1,o=1;
struct f{
ll a;
ll b;
ll id;
bool operator <(const f &x)const{
return a+b>x.a+x.b;
}
}x[maxn];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&x[i].a);
x[i].id=i;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&x[i].b);
}
sort(x+1,x+1+n);
for(int i=1;i<=n;i=i+2)
printf("%lld ",x[i].id);
printf("\n");
for(int i=2;i<=n;i=i+2)
printf("%lld ",x[i].id);
printf("\n");
}
G-判正误
题目要求及相关数据:
重点:附上出题人说的
可见本题重点是取模
代码1:这样看赛后写的这个代码也是占了pow的空子,等等学点新的方法再写个
#include<bits/stdc++.h>
using namespace std;
const long long maxn=1e9+9;//这个题有点坑,出题人觉得思路容易做就在模数上下了点套
typedef long long ll ;//取1e9+7/8就不过,取1e9+9就过了
ll gaoshi(ll a,ll b)//这个函数很好取模数的板子
{
if(b==0) return 1;
if(b%2==1) return a*gaoshi(a,b-1)%maxn;
else {
ll m=gaoshi(a,b/2);
return m*m%maxn;
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
long long a,b,c,d,e,f,g,x,y,z;
scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g);
if(g!=0)
{
x=gaoshi(a,d);
y=gaoshi(b,e);
z=gaoshi(c,f);
if(x+y+z==g)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
else{
if(pow(a,d)+pow(b,e)+pow(c,f)==g) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
}
代码2(正解).
#include<bits/stdc++.h>
using namespace std;
const long long maxn=1e9+7;
typedef long long ll ;
ll quick(ll a,ll b)
{ ll ans=1;
while(b>0){
if(b&1)
{
ans=ans*a%maxn;
}
a=a*a%maxn;
b>>=1;
}
return ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
long long a,b,c,d,e,f,g,x=maxn,y=0,z=0;
scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g);
if(quick(a,d)+quick(b,e)+quick(c,f)==g%maxn)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
H 施魔法
题目要求及相关数据:
出题人写的前缀和的方法我没搞懂,有空时再琢磨琢磨
解法:我们贪心一下,要让使用的魔力少,则必须在连续的区间中取元素,这个可以通过快排来解决,然后通过这个题我也明白一点动态规划的意义,在这个题中动态规划是一种枚举,是每一个前面可以到达现在这一步的集合,而要取的就是集合中的最小值,因为至少取k个,所以要从k+1开始进行动态规划,对于K+1~n的dp[i](dp[i]代表以i为结尾的所消耗的最小魔力)来说,有两种情况:1.这个dp[i]可以连起来作为前一个dp[i-1]的尾那么状态转移方程就是dp[i]=dp[i-1]-a[i-1]+a[i](注意:一段区间就一个尾和一个头,若成新区间则要变结尾)2.i作为一段(dp[i-k])的新尾,那么一段的头就可以用i-k+1来表示,由于凑成了新的一段,所以头尾都变了,然后加上之前消耗的最小魔力值,方程:dp[i]=dp[i-k]-a[i-k+1]+a[i](保证新一段还是为该段最大值减最小值) 最后取这两种情况的最小值。
代码:
#include<bits/stdc++.h>
using namespace std;
const int w=0x3f3f3f3f;
const int maxn=3e5+10;
typedef long ll;
ll a[maxn],dp[maxn];
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i]=w;
}
sort(a+1,a+1+n);
dp[k]=a[k]-a[1];
for(int i=k+1;i<=n;i++)
{
dp[i]=min(dp[i-1]-a[i-1]+a[i],dp[i-k]-a[i-k+1]+a[i]);
}
cout<<dp[n]<<endl;
}
I.建通道
考察:二进制、权值
还没学待补
J. 求函数
考察:线段树
还没学待补