crp week3周报

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

每一轮重复如下过程:

  1. X=X+aP​​
  2. 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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值