1.积木大赛
noip 2018 2013 d1t1
难度不是很大 画个图就好了
首先 你叠积木肯定会叠成金字塔形状的 对8?qaq
由图可知 我们可以发现一个事实
我们覆盖最长的则是最优(这好像是废话)
并且 一个相对于之前那个点是上升的
我们就要付出多少代价
这个点是下降的 我们不会付出代价的!!!
从左端点进行统计就好了 !
#include<iostream>
using namespace std;
int now,ans,n,a;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a;
if(a>now) ans+=a-now;
now=a;
}
cout<<ans;
return 0;
}
2.小凯的疑惑
数学好的同学可以用裴蜀定理
而像我这种蒟蒻可以打暴力或者直接找规律qaq
//baoli
#include<iostream>
using namespace std;
int flag[1000010];
int main()
{
int a,b,x,y;
cin>>a>>b;
for(x=0;x<=1000;x++)
for(y=0;y<=1000;y++)
flag[a*x+b*y]=1;
for(int i=1000;i>=0;i--)
if(flag==0) cout<<i;
return 0;
}
//gcd(a,b)=1;
/*
3 7
1,2,4,5,8,11,
3*4=12
3+7+3=13
7*2
*/
#include<iostream>
using namespace std;
int main()
{
long long a,b;
cin>>a>>b;
cout<<a*b-a-b;
return 0;
}
/* 我在这里找的规律
3 4 5 6 (3-1)*(4-1)
3 5 7 8 (3-1)*(5-1)
3 7 11 12 (3-1)*(7-1)
(a-1)(b-1)==ab-a-b
*/
----------第三题麦森数
一、求位数
首先我们知道 与 有着相同的位数,因为2的次方满足了最后一位不为零的要求,所以减一后位数并不会改变,那么我们可以直接求 的位数。那么怎么求位数呢?我们不妨设 ,根据 的位数为 ,我们只要想办法把 中的底数2改为10,指数加一就是位数了。由此想到用10的几次方来代替2,那么就不难想到 ,这样便可以把 中的2代换掉,变为 。根据乘方的原理,将p乘进去,原式便可化为我们最终想要的形式 了,所以位数就是 。(提醒一下,C++中cmath库自带log10()函数…)//某人的博客
或者可以这想
N = 10 -> 位数为2;
N = 100 -> 位数为3;
N = 1000 -> 位数为4;
N = 12345 -> 位数为5;
可见自然数N的位数等于lg(N) + 1
所以,2的p次方减1的位数为:lg(2^p-1) + 1。有同学到这里就懵了,不会解,赶紧百度-_-。
我看到网站上很多就是直接求 lg(2^p)+1,而题目是求2^p-1的位数,为什么这里是2^p。跳的太快了,我脑壳疼。
其实,求2^p-1的位数和2^p的位数相同。(如果2^p-1和2^p的位数不同的话,只有2^p是10的倍数:
10,100, 1000…。如10减1等于9,9只有1位数,而10有两位数。可知2的N次方是:2,4,8,16,3,264…,尾数是2,4,6,8…,不会出现10的倍数)
所以,求2的p次方减1的位数,可以转化为求2的p次方的位数: lg(2^p)+1
这样,我们就可以利用数学公式lg(m^n) = mlg(n)将: lg(2^p)+1 ----> plg(2)+1
这就简单很多了。()
//这个是dalao的博客
第二问难点就在高精度乘法 还有快速幂上
快速幂不会的赶紧去y总那看模板!!
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
int f[1001];//chengji
int p,res[1001],sav[1001];
void ult1()
{
memset(sav,0,sizeof(sav));
for(int i=1;i<=500;i++)
for(int j=1;j<=500;j++)
sav[i+j-1]+=res[i]*f[j];
for(int i=1;i<=500;i++)
{
sav[i+1]+=sav[i]/10;
sav[i]%=10; //解决进位
}
memcpy(res,sav,sizeof(res));
}
void ult2()
{
memset(sav,0,sizeof(sav));
for(int i=1;i<=500;i++)
for(int j=1;j<=500;j++)
sav[i+j-1]+=f[i]*f[j];// 将乘积变大
for(int i=1;i<=500;i++)
{
sav[i+1]+=sav[i]/10;
sav[i]%=10; //解决进位
}
memcpy(f,sav,sizeof(f));
}
int main()
{
cin>>p;
cout<<(int)(log10(2)*p+1)<<endl;
res[1]=1;//初始化结果
f[1]=2;
while(p!=0)
{
if(p%2==1) ult1();
p/=2;
ult2();
}
res[1]=res[1]-1;
for(int i=500;i>=1;i--)
if(i!=500&&i%50==0) printf("\n%d",res[i]);
else cout<<res[i];
return 0;
}
这个题主要是注意细节就好了
第四题
表达式求值
while(scanf(“%d%[+]”,&a[n],&op[n])==2)n++;
/一个非常好的用法,省了很多事
每次输入一个整数和一个符号,符号是在+和中选一个
scanf返回读到的个数,如果不是两个(说明只读到了最后一个整数)
到么字符串就结束了,停止读入,n记录一共有多少个数(共有n-1个符号)/
我就想讲这一个(一个小trick)
https://www.acwing.com/problem/content/513/
联合权值
这个应该结合图片 但我不会上传 5555
这是一道统计题 首先就找特征
很明显 我们可以想到枚中间点来做这个题
第一问很容易解决 找到wx*wy最大的就好了
我们通过菊花图可以发现一个定理
我们要求的是 2wab+2wbc+2wcd+2wda
(a+b+c+d)²=a²+b²+c²+d²+a(b+c+d)+b(a+c+d)+c(a+b+d)+d(a+b+c)
移项得
(a+b+c+d)²-a²+b²+c²+d²=2wab+2wbc+2wcd+2wda
这就是我们想要的答案
#include<cstdio>
using namespace std;
struct edge
{
int next;
int to;
}a[400005];
int edgenum,head[200005],w[200005];
int n,ans,maxx;
void add(int u,int v)//加入一条从u到v的边
{
a[++edgenum].next=head[u];
a[edgenum].to=v;
head[u]=edgenum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
{
int max1=0,max2=0;//最大的两个权值
int t1=0,t2=0;//t1代表和的平方,t2代表平方和
for(int j=head[i];j;j=a[j].next)
{
if(w[a[j].to]>max1)max2=max1,max1=w[a[j].to];
else if(w[a[j].to]>max2)max2=w[a[j].to];
t1=(t1+w[a[j].to])%10007;
t2=(t2+w[a[j].to]*w[a[j].to])%10007;
}
t1=t1*t1%10007;
ans=(ans+t1+10007-t2)%10007;
if(maxx<max1*max2)maxx=max1*max2;
}
printf("%d %d\n",maxx,ans);
return 0;
}
最后一道题 :魔法阵
根据这个xa<xb<xc<xd,xb−xa=2(xd−xc),并且xb−xa<(xc−xb)/3 时,画图就好
#include<cstdio>
using namespace std;
int n,m;
int v[40010],num[15010];
int a[15010],b[15010],c[15010],d[15010];
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i ++){
scanf("%d",&v[i]);
num[v[i]]++;//桶排序
}
for(int t = 1; t * 9 < n; t++){ //枚举t
int sum = 0;
int va,vb,vc,vd;
for(vd = t * 9 + 2; vd <= n; vd++){//枚举 d 物品的位置
va = vd - 9 * t - 1;//a 物品的魔法值
vb = vd - 7 * t - 1;//b 物品的魔法值
vc = vd - t;//c 物品的魔法值
sum += num[vb] * num[va]; //前缀和求能组成的魔法阵的个数
c[vc] += num[vd] * sum;
d[vd] += num[vc] * sum;
}
sum = 0;
for(va = n - t * 9 - 1; va >= 1; va--){//枚举 a 物品的位置
vb = va + 2 * t;
vc = va + t * 8 + 1;
vd = va + t * 9 + 1;
sum += num[vc] * num[vd];
a[va] += num[vb] * sum;
b[vb] += num[va] * sum;
}
}
for(int i = 1; i <= m; i++)
printf("%d %d %d %d\n", a[v[i]],b[v[i]],c[v[i]],d[v[i]]);
}
有个疑问 noip 能用 ios::sync_with_stdio(false) 吗, freopen后 需不需要fclose(stdin)?
建议把标题改为
NOIP 题目总结
之类的会更清晰~非常感谢!
好棒啊!
谢谢!