一。递归与递推
方法: 思维模式,找本题所用的思想,找到目标组数,创建数组按顺序依次选择被选择的数---问题边界-----记录该数已选---求解子问题---回溯到上一问题,还原现场
常与枚举使用
例题:ch201 费解的开关(递归实现枚举,状态压缩)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int pic[6][6];//存储输入 6 int tmppic[6][6];//临时复制数组 7 int di[]={0,0,0,1,-1}; 8 int dj[]={0,1,-1,0,0}; 9 10 void turn(int i,int j){//反转 11 for(int k=0;k<5;k++){ 12 int tmpi=i+di[k],tmpj=j+dj[k]; 13 if(tmpi>=1 && tmpi<=5 && tmpj>=1 && tmpj<=5) 14 { 15 if(tmppic[tmpi][tmpj]==1) tmppic[tmpi][tmpj]=0; 16 else tmppic[tmpi][tmpj]=1; 17 } 18 } 19 } 20 21 bool test(int i){//检测答案 22 for(int j=1;j<=5;j++){ 23 if(tmppic[i][j]!=1) return false; 24 } 25 return true; 26 } 27 28 int solve(){ 29 int minans=25; 30 for(int i=0;i<(1<<5);i++){ 31 memcpy(tmppic,pic,sizeof(pic)); 32 int ans=0; 33 for(int j=0;j<5;j++){ 34 if((i>>j)&1) {turn(1,j+1);ans++;} 35 } 36 for(int j=2;j<=5;j++){ 37 for(int k=1;k<=5;k++){ 38 if(tmppic[j-1][k]==0){ 39 turn(j,k); 40 ans++; 41 } 42 } 43 } 44 if(test(5)) minans=min(minans,ans); 45 } 46 return minans; 47 } 48 49 int main(){ 50 int t; 51 scanf("%d",&t); 52 while(t--){ 53 char tmp; 54 for(int i=1;i<=5;i++){ 55 for(int j=1;j<=5;j++){ 56 tmp=getchar(); 57 while(tmp!='0'&&tmp!='1') tmp=getchar(); 58 pic[i][j]=tmp-'0'; 59 } 60 } 61 int ans=solve(); 62 printf("%d ",ans>6?-1:ans); 63 } 64 return 0; 65 }
方法:先枚举第一行的开关情况,再每个情况往下一行推看最后一行是否满足要求,则方案数+1
核心:
for(int j = 0; now; j++, now >>= 1) {
if(now & 1) press(0,j);
}
思考:看到这类题先想用递归枚举法是否比dfs要更简便,因为本题只要枚举第一行的情况之后每个情况的答案都只有一种,所以用递归枚举法更方便。先找思想,思维模式考虑是否其实情况答案唯一可以用递归枚举进行状态压缩,若每个情况都会分成更细的子问题则用dfs等搜索更优,不适合再用递归枚举(只适合结果单一不复杂)。
poj1845(递归分治)/(数论 逆元+快速幂)
要求的是A^B的所有因子的和之后再mod 9901的值。
因为一个数A能够表示成多个素数的幂相乘的形式。即A=(a1^n1)*(a2^n2)*(a3^n3)...(am^nm)。所以这个题就是要求
(1+a1+a1^2+...a1^n1)*(1+a2+a2^2+...a2^n2)*(1+a3+a3^2+...a3^n2)*...(1+am+am^2+...am^nm) mod 9901。
对于每一个(1+a1+a1^2+...a1^n1) mod 9901
等于 (a1^(n1+1)-1)/(a1-1) mod 9901,这里用到逆元的知识:a/b mod c = (a mod (b*c))/ b
所以就等于(a1^(n1+1)-1)mod (9901*(a1-1)) / (a1-1)。
至于前面的a1^(n1+1),快速幂。‘
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <vector> 5 #include <string> 6 #include <cstring> 7 #pragma warning(disable:4996) 8 using namespace std; 9 #define M 9901 10 11 long long p[50005]; 12 int prime[50005]; 13 14 void isprime() 15 { 16 int cnt = 0, i, j; 17 memset(prime, 0, sizeof(prime)); 18 19 for (i = 2; i < 50005; i++) 20 { 21 if (prime[i] == 0) 22 { 23 p[++cnt] = i; 24 for (j = 2 * i; j < 50005;j=j+i) 25 { 26 prime[j] = 1; 27 } 28 } 29 } 30 } 31 32 long long multi(long long A,long long n,long long k) 33 { 34 long long b=0; 35 while(n>0) 36 { 37 if(n&1) 38 { 39 b=(b+A)%k; 40 } 41 n=n>>1; 42 A=(A+A)%k; 43 } 44 return b; 45 } 46 47 long long getresult(long long A,long long n,long long k) 48 { 49 long long b = 1; 50 while (n > 0) 51 { 52 if (n & 1) 53 { 54 b=multi(b,A,k); 55 } 56 n = n >> 1; 57 A=multi(A,A,k); 58 } 59 return b; 60 } 61 62 void solve(long long A, long long B) 63 { 64 int i; 65 long long ans = 1; 66 for (i = 1; p[i] * p[i] <= A; i++) 67 { 68 if (A%p[i] == 0) 69 { 70 int num = 0; 71 while (A%p[i] == 0) 72 { 73 num++; 74 A = A / p[i]; 75 } 76 long long m = (p[i] - 1) * 9901; 77 ans *= (getresult(p[i], num*B + 1, m) + m - 1) / (p[i] - 1); 78 ans %= 9901; 79 } 80 } 81 if (A > 1) 82 { 83 long long m = 9901 * (A - 1); 84 ans *= (getresult(A, B + 1, m) + m - 1) / (A - 1); 85 ans %= 9901; 86 } 87 cout << ans << endl; 88 } 89 90 int main() 91 { 92 //freopen("i.txt","r",stdin); 93 //freopen("o.txt","w",stdout); 94 95 long long A, B; 96 97 isprime(); 98 99 while (cin>>A>>B) 100 { 101 solve(A, B); 102 } 103 return 0; 104 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cmath> #include <iostream> #include <algorithm> using namespace std; const int mod=9901; int pow_mod(int a,int b) { a=a%mod; int s=1; while(b) { if(b&1) s=(s*a)%mod; a=(a*a)%mod; b=b>>1; } return s; } int sum(int a,int b)//求1+a+a^2+...+a^b { if(b==1)return 1; if(b&1)return (sum(a,b/2)*(1+pow_mod(a,b/2+1))+pow_mod(a,b/2))%mod; else return sum(a,b/2)*(1+pow_mod(a,b/2))%mod; } int main() { int a,b; while(cin>>a>>b) { if(a<=1||b==0){cout<<1<<endl;continue;} int ans=1,i,j,k,t,n,m; n=(int)sqrt(a+0.5); for(i=2;i<=n;i++) { if(a%i==0) { t=0; while(a%i==0){ a=a/i; t++; } ans=ans*sum(i,t*b+1)%mod; } } if(a>1) ans=ans*sum(a,b+1)%mod; cout<<(ans+mod)%mod<<endl; } return 0; }
思考:看到这类偏数学的题立马想思维,想数学公式与逆元,快速幂等数学方法,手写推导,此题需要考虑次方的奇偶性
poj3889(分形)(坐标变换)
参考:https://blog.csdn.net/ben_xsy/article/details/79288058