超链接为pdf题面,请先登录。
一看了数据范围,就应该想到找规律了。在推一推,你会发现,这道题如果不用高精度的话,绝对炸裂!
而有一些“Lucky dog”就是往死里钻→
首先用暴力试一试,将n<=10的解算出来,然后找规律:
大家有没有发现,每一个解要么以1结尾,要么以9结尾。
我就是这样想出规律的:
当n=1时,ans=101-91
当n=2时,ans=102-92
当n=3时,ans=103-93
则ans=10n-9n
高精乘请看最后一个题目。
LAW code:
#include
using namespace std;
int str,n,a[2010];
int main()
{
// freopen("typewrt.in","r",stdin);
// freopen("typewrt.out","w",stdout);
scanf("%d",&n);
a[1]=1;
if(n==1)
{
printf("1\n");
return 0;
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=1500;j++)
{
a[j]=a[j]*9+a[j-1]/10;
a[j-1]%=10;
}
a[i]++;
str=1500;
while(!a[str])
str--;
}
for(int i=str;i>=1;i--)
printf("%d",a[i]);
printf("\n");
fclose(stdin);
fclose(stdout);
return 0;
}
一个裸尾巴的背包问题,每个数的大小可以看作是物品的重量,每个数的约数和可以看作是物品的价值,然后就用常规01背包,就可以了。
背包问题知识点超链接
#include
#include
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int sum[1010],n,mx;
int f[1010];
int ys(int x)
{
int i,sum=0;
for(i=1;i<x;i++)
if(x%i==0)
sum+=i;
return sum;
}
void dp()
{
for(int i=1;i<=n;i++)
for(int j=n;j>=i;j--)
f[j]=max(f[j],f[j-i]+sum[i]);
for(int i=1;i<=n;i++)
if(f[i]>mx)
mx=f[i];
}
int main()
{
// freopen("maxsum.in","r",stdin);
// freopen("maxsum.out","str",stdout);
scanf("%d",&n);
for(int i=2;i<=n;i++)
sum[i]=ys(i);
dp();
printf("%d\n",mx);
fclose(stdin);
fclose(stdout);
return 0;
}
//每个数的大小可以看作是物品的重量,每个数的约数和可以看作是物品的价值
队列的应用与实现。首先大家需要掌握几个重要队列函数。
首先,在代码上打上头文件 #include< queue >
常用的成员函数如下:
队列中由于是先进先出,push即在队尾插入一个元素,如:
queue<string> q;
q.push("Hello World!");
q.push("China");
cout<<q.front()<<endl;
可以输出:Hello World!
将队列中最靠前位置的元素拿掉,是没有返回值的void函数。如:
queue<string> q;
q.push("Hello World!");
q.push("China");
q.pop();
cout<<q.front()<<endl;
返回队列中元素的个数,返回值类型为unsigned int。如:
queue q;
cout<<q.size()<<endl;
q.push(“Hello World!”);
q.push(“China”);
cout<<q.size()<<endl;
判断队列是否为空的,如果为空则返回true。如:
1 queue q;
2 cout<<q.empty()<<endl;
3 q.push(“Hello World!”);
4 q.push(“China”);
5 cout<<q.empty()<<endl;
返回值为队列中的第一个元素,也就是最早、最先进入队列的元素。注意这里只是返回最早进入的元素,并没有把它剔除出队列。如:
queue<string> q;
q.push("Hello World!");
q.push("China");
cout<<q.front()<<endl;
q.pop();
cout<<q.front()<<endl;
输出值为两行,分别是Hello World!和China。只有在使用了pop以后,队列中的最早进入元素才会被剔除。
返回队列中最后一个元素,也就是最晚进去的元素。如:
queue q;
q.push(“Hello World!”);
q.push(“China”);
cout<<q.back()<<endl;
输出值为China,因为它是最后进去的。这里back仅仅是返回最后一个元素,也并没有将该元素从队列剔除掉。
QUE code:
#include
#include
using namespace std;
const int N=100050;
queue<int> q;
int a,n,m,tot=0,sj[N],ans;
int last[N],zk[N];//1:生病 0:可感染 2:抗感染
struct node{
int next,to;
}edge[2*N];
void add(int to,int sta){
edge[++tot].to=to;
edge[tot].next=last[sta];
last[sta]=tot;
edge[++tot].to=sta;
edge[tot].next=last[to];
last[to]=tot;
}
int main(){
freopen("flu.in","r",stdin);
freopen("flu.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d %d",&x,&y);
add(y,x);
}
scanf("%d",&a);
q.push(a);zk[a]=1;sj[a]=1;
while(!q.empty()){
int i=q.front();q.pop();
ans=max(ans,sj[i]);
// printf("%d号学生 状况:%d 时间:%d\n",i,zk[i],sj[i]);
for(int j=last[i];j;j=edge[j].next){
if(!zk[edge[j].to] && sj[edge[j].to]<=sj[i]){
q.push(edge[j].to);
zk[edge[j].to]=1;
sj[edge[j].to]=sj[i]+1;
//printf("%d号学生 状况:%d 时间:%d\n",edge[j].to,zk[edge[j].to],sj[edge[j].to]);
}
}
zk[i]=2;sj[i]++;
}
printf("%d",ans);
return 0;
}
裸高精度,十分容易。
对于高精乘高精,请观察一下图片:
分析c数组下标的变化规律,可以写出如下关系式:ci = c’i +c”i +…由此可见,c i跟a[i]*b[j]乘积有关,跟上次的进位有关,还跟原c i的值有关,分析下标规律,有c[i+j-1]= a[i]*b[j]+ x + c[i+j-1]; x=c[i+j-1]/10 ; c[i+j-1]%=10;
以上为dalao lzoi_hmh 的资料。
HPM code:
#include
#include
#include
using namespace std;
char str1[50],str2[50];
int a[50],b[50],c[100],len;
int main()
{
// freopen("bullmath.in","r",stdin);
// freopen("bullmath.out","w",stdout);
scanf("%s",&str1);
scanf("%s",&str2);
a[0]=strlen(str1);
b[0]=strlen(str2);
for(int i=1;i<=a[0];i++)
a[i]=str1[a[0]-i]-'0';
for(int i=1;i<=b[0];i++)
b[i]=str2[b[0]-i]-'0';
for(int i=1;i<=a[0];i++)
for(int j=1;j<=b[0];j++)
{
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/10;
c[i+j-1]%=10;
}
len=a[0]+b[0]+1;
while((!c[len])&&(len>1))
len--;
for(int i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n");
fclose(stdin);
fclose(stdout);
return 0;
}