P1028 [NOIP2001 普及组] 数的计算
1.思路:找规律,先列前面几项,找到递推式
2.代码:
#include <bits/stdc++.h>
using namespace std;
int f[1005];
int dfs(int x)
{
if(f[x]) return f[x];
if(x%2==0) f[x]=dfs(x-1)+dfs(x/2);
if(x%2==1) f[x]=dfs(x-1);
return f[x];
}
int main()
{
int n;
cin>>n;
f[1]=1;
f[2]=2;
cout<<dfs(n);
}
P1192 台阶问题
1.思路:记忆化搜索,如果直接递推容易超时
2.代码:
#include <bits/stdc++.h>
using namespace std;
int f[100005];
int n;
int k;
long long dfs(int x)
{
if(f[x]) return f[x];
for(int i=1;i<=k;i=i+1)
{
f[x]=(f[x]+dfs(x-i))%100003;
}
return f[x];
}
int main()
{
cin>>n;
cin>>k;
f[0]=1;
f[1]=1;
for(int i=2;i<=k;i=i+1)
{
for(int j=0;j<i;j=j+1)
{
f[i]=(f[i]+f[j])%100003;
}
}
cout<<dfs(n);
}
P1044 [NOIP2003 普及组] 栈
1.思路:枚举几个方案数,发现符合卡特兰数规律,直接代公式做出答案,但是要用高精度做,不然答案会错
2.代码:
#include <bits/stdc++.h>
using namespace std;
string add(string str1,string str2)
{
string str;
int len1=str1.length();
int len2=str2.length();
if(len1<len2)
{
for(int i=1;i<=len2-len1;i++)
{
str1="0"+str1;
}
}
else
{
for(int i=1;i<=len1-len2;i=i+1)
{
str2="0"+str2;
}
}
len1=str1.length();
int cf=0;
int temp;
for(int i=len1-1;i>=0;i=i-1)
{
temp=str1[i]-'0'+str2[i]-'0'+cf;
cf=temp/10;
temp%=10;
str=char(temp+'0')+str;
}
if(cf!=0)str=char(cf+'0')+str;
return str;
}
string mul(string str1,string str2)
{
string str;
int len1=str1.length();
int len2=str2.length();
string tempstr;
for(int i=len2-1;i>=0;i--)
{
tempstr="";
int temp=str2[i]-'0';
int t=0;
int cf=0;
if(temp!=0)
{
for(int j=1;j<=len2-1-i;j=j+1)
{
tempstr+="0";
}
for(int j=len1-1;j>=0;j--)
{
t=(temp*(str1[j]-'0')+cf)%10;
cf=(temp*(str1[j]-'0')+cf)/10;
tempstr=char(t+'0')+tempstr;
}
if(cf!=0)
{
tempstr=char(cf+'0')+tempstr;
}
}
str=add(str,tempstr);
}
str.erase(0,str.find_first_not_of('0'));
return str;
}
string mult(string a,int b)
{
int i=0,tag=0,la=a.size();
int d=0;
string c;
while(i<=la)
{
if(b>d)
{
d=d*10+a[i++]-'0';
if(tag)c=c+"0";
}
else
{
c=c+char(d/b+'0');
d=d%b;
d=d*10+a[i++]-'0';
tag=1;
}
}
if(tag==0)
{
c=c+"0";
}
return c;
}
string doit(int a)
{
string b;
while(a>0)
{
b=char(a%10+'0')+b;
a/=10;
}
return b;
}
int main()
{
int n;
cin>>n;
string s="1";
for(int i=n+1;i<=2*n;i=i+1)
{
string h=doit(i);
s=mul(s,h);
}
for(int i=1;i<=n+1;i=i+1)
{
s=mult(s,i);
}
cout<<s;
}
P1003 [NOIP2011 提高组] 铺地毯
1.思路:从最后一个地毯往前铺,什么时候把格子铺住了什么时候停
2.代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
int x,y;
int m=-1;
cin>>n;
int a[n+1],b[n+1],g[n+1],k[n+1];
for(int i=1;i<=n;i=i+1)
{
cin>>a[i]>>b[i]>>g[i]>>k[i];
}
cin>>x>>y;
for(int i=n;i>=1;i=i-1)
{
if(x>=a[i]&&x<=a[i]+g[i]&&y>=b[i]&&y<=b[i]+k[i])
{
cout<<i;
break;
}
else
{
if(i==1)
{
cout<<m;
}
}
}
}
P4994 终于结束的起点
1.思路:给了递推公式,直接用,但需要记忆化搜索
2.代码:
#include <bits/stdc++.h>
using namespace std;
int f[10000007];
int m;
long long dfs(int x)
{
if(f[x])return f[x];
f[x]=(dfs(x-1)+dfs(x-2))%m;
return f[x];
}
int main()
{
cin>>m;
int num1=1;
f[0]=0;
f[1]=1;
f[2]=1;
while(dfs(num1)!=0||dfs(num1+1)!=1)
{
num1++;
}
cout<<num1;
}
P2615 [NOIP2015 提高组] 神奇的幻方
1.思路:按题意列举情况即可
2.代码:
#include <bits/stdc++.h>
using namespace std;
int f[40][40];
int n;
int k=1;
void dfs(int x,int y)
{
if(k==n*n)return;
k=k+1;
if(x==1&&y!=n)
{
f[n][y+1]=k;
dfs(n,y+1);
}
else if(y==n&&x!=1)
{
f[x-1][1]=k;
dfs(x-1,1);
}
else if(x==1&&y==n)
{
f[x+1][y]=k;
dfs(x+1,y);
}
else
{
if(f[x-1][y+1])
{
f[x+1][y]=k;
dfs(x+1,y);
}
else
{
f[x-1][y+1]=k;
dfs(x-1,y+1);
}
}
}
int main()
{
cin>>n;
f[1][n/2+1]=1;
dfs(1,n/2+1);
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=n;j=j+1)
{
if(j!=n)
{
cout<<f[i][j]<<" ";
}
else
{
cout<<f[i][j]<<endl;
}
}
}
}
P1011 [NOIP1998 提高组] 车站
1.思路:枚举前几个情况,找到规律:这一次的系数等于前两次的系数相加,斐波那契数列。
2.代码:
#include <bits/stdc++.h>
using namespace std;
int f[40][40];
int n;
int k=1;
void dfs(int x,int y)
{
if(k==n*n)return;
k=k+1;
if(x==1&&y!=n)
{
f[n][y+1]=k;
dfs(n,y+1);
}
else if(y==n&&x!=1)
{
f[x-1][1]=k;
dfs(x-1,1);
}
else if(x==1&&y==n)
{
f[x+1][y]=k;
dfs(x+1,y);
}
else
{
if(f[x-1][y+1])
{
f[x+1][y]=k;
dfs(x+1,y);
}
else
{
f[x-1][y+1]=k;
dfs(x-1,y+1);
}
}
}
int main()
{
cin>>n;
f[1][n/2+1]=1;
dfs(1,n/2+1);
for(int i=1;i<=n;i=i+1)
{
for(int j=1;j<=n;j=j+1)
{
if(j!=n)
{
cout<<f[i][j]<<" ";
}
else
{
cout<<f[i][j]<<endl;
}
}
}
}
递推学习心得
一.两种思路:1.假设f(1).....f(n)都已完成,思考f(n)可以完成的情况得状态转移方程
2.从前往后找规律,总结关系,如果符合卡特兰数,可以直接按公式算出方案数
二.记忆化搜索:写时就写记忆化搜索,可以有效防止超时
周赛补题
7-2 添加括号
现在给出一个表达式,形如 a1/a2/a3/.../an。
如果直接计算,就是一个个除过去,比如 1/2/1/4=1/8。
然而小A看到一个分数感觉很不舒服,希望通过添加一些括号使其变成一个整数。一种可行的办法是 (1/2)/(1/4)=2 。
现在给出这个表达式,求问是否可以通过添加一些括号改变运算顺序使其成为一个整数。
一个测试点中会有多个表达式。
第一行 t ,表示表达式数量。
对于每个表达式,第一行是 n,第二行 n 个数,第 i 个数表示 ai。
2≤n≤10000,1≤t≤100,1≤ai≤231−1。
输出 t 行。
对于每个表达式,如果可以通过添加括号改变顺序使其变成整数,那么输出 Yes
,否则输出 No
。
2
4
1 2 1 4
5
6 5 7 9 12
Yes
No
代码长度限制
64 KB
时间限制
1000 ms
内存限制
256 MB
1.思路:比较不容易发现,只有第二个数是一定做分母的,其他数都可以做分子,所以只要保证其他数相乘可以整除第二个数即可
2.代码:
#include <bits/stdc++.h>
using namespace std;
long long a[10005];
long long gcd(long long x,long long y)
{
long long c;
c=x%y;
while(c!=0)
{
x=y;
y=c;
c=x%y;
}
return y;
}
int main()
{
int t;
cin>>t;
for(int i=1;i<=t;i=i+1)
{
int n;
cin>>n;
for(int j=1;j<=n;j=j+1)
{
cin>>a[j];
}
long long h=a[2];
for(int j=1;j<=n;j=j+1)
{
if(j==2)
{
continue;
}
else
{
long long b=gcd(a[j],h);
h=h/b;
}
}
if(h==1)
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
}
7-5 线性变换
小F有一个序列 a0,a1,a2,...,an−1,他决定进行 T 轮操作,来产生一个加密值 X。
在一开始,他有一个下标 P,一对线性变换系数 K、B,加密值 X 的初始值为 0
每一轮重复如下过程:
- X=X+aP
- P=(K×P+B)%n
请你帮他计算这个加密值 X 最后是多少。
第一行输入五个整数 n,P,K,B,T(1≤n≤106,0≤P<n,0≤K,B≤106,0≤T≤1012)
第二行输入 n 个整数 a0,a1,a2...an−1(0≤ai≤106),表示这个序列。
输出一个整数,表示最终的加密值X
7 1 1 3 4
1 4 2 2 5 10 1
12
8 3 2 0 2
1 2 3 4 8 7 6 5
10
对于样例1,四轮操作依次为:,
第一轮:P=1,X=0+4=4
第二轮:P=(1×1+3)%n=4,X=4+5=9
第三轮:P=(1×4+3)%n=0,X=9+1=10
第四轮:P=(1×0+3)%n=3,X=10+2=12
1.思路:找到循环数列,那么后面就不用再进行操作,将会一直按着这个数列进行
2.代码:
#include <bits/stdc++.h>
using namespace std;
int a[1000015];
int vis[1000015];
vector<int> v;
int main()
{
int n,p,k,b;
long long t;
cin>>n>>p>>k>>b;
cin>>t;
for(int i=0;i<n;i=i+1)
{
cin>>a[i];
}
vis[p]=1;
v.push_back(p);
long long x=0;
x=x+a[p];
p=(k*p+b)%n;
long long now=-1;
int nowhh;
for(long long i=2;i<=t;i=i+1)
{
if(vis[p]==1)
{
now=i;
nowhh=find(v.begin(),v.end(),p)-v.begin();
break;
}
else
{
vis[p]=1;
v.push_back(p);
x=x+a[p];
p=(k*p+b)%n;
}
}
if(t==0)
{
cout<<0;
}
else if(now==-1)
{
cout<<x;
}
else
{
long long r=(t-now+1)/(v.size()-nowhh);
long long rr=(t-now+1)%(v.size()-nowhh);
for(int i=nowhh;i<v.size();i++)
{
if(i<rr)
{
x=x+a[v[i]]*(r+1);
}
else
{
x=x+a[v[i]]*r;
}
}
cout<<x<<endl;
}
}