AcWing 896. 最长上升子序列 II
//f[i]:长为i的LIS末位的最小值 #include #include #include using namespace std; int f[1000010]; int main(){ memset(f,0x3f,sizeof(f)); int n; cin>>n; for(int i = 1; i <= n; i++){ int x; cin>>x; *lower_bound(f+1,f+n+1,x) = x; } cout<AcWing 897. 最长公共子序列
//f[i][j]表示到a[i]和b[j]为止的lCS。转移,显而易见。 #include using namespace std; int f[1010][1010]; int main(){ int n, m; cin>>n>>m; string a, b; cin>>a>>b; for(int i = 0; i < a.size(); i++){ for(int j = 0; j < b.size(); j++){ if(a[i]==b[j])f[i+1][j+1] = f[i][j]+1; else f[i+1][j+1] = max(f[i][j+1],f[i+1][j]); } } cout<AcWing 902. 最短编辑距离
//题意:给出两个字符串a和b,将a通过删除,插入,替换变换成b,求最少操作次数。 //思路:f[i][j]表示将a[1~i]变成b[1~j]的最小操作次数,转移的时候分别考虑删除,插入和替换即可。 #include using namespace std; const int maxn = 1010; int f[maxn][maxn]; int main(){ int n, m; string a, b; cin>>n>>a>>m>>b; a = "0"+a; b = "0"+b; memset(f,0,sizeof(f)); for(int i = 1; i <= n; i++)f[i][0] = i;//只能删除 for(int i = 1; i <= m; i++)f[0][i] = i;//只能插入 for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ f[i][j] = min(f[i-1][j]+1,f[i][j-1]+1);//删除a[i]或插入b[j]使之匹配, 次数+1 if(a[i]==b[j])f[i][j] = min(f[i][j],f[i-1][j-1]);//本来就相等 else f[i][j] = min(f[i][j],f[i-1][j-1]+1);//修改a[i]或b[j] } } cout<AcWing 899. 编辑距离
//题意:给出n个字符串和m个询问,每次询问n个串中有多少个可以在k次操作(插入, 删除, 替换)内变成给出的字符串t //思路:多跑几遍上题的最短编辑距离就行,m*(n*10^2)=1e8 #include using namespace std; const int maxn = 1010; string s[maxn]; //计算次数 int f[maxn][maxn]; int dist(string a, string b){ int n=a.size(), m=b.size(); a = "0"+a; b = "0"+b; //memset(f,0,sizeof(f)); for(int i = 1; i <= n; i++)f[i][0] = i;//只能删除 for(int i = 1; i <= m; i++)f[0][i] = i;//只能插入 for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ f[i][j] = min(f[i-1][j]+1,f[i][j-1]+1);//删除a[i]或插入b[j]使之匹配, 次数+1 if(a[i]==b[j])f[i][j] = min(f[i][j],f[i-1][j-1]);//本来就相等 else f[i][j] = min(f[i][j],f[i-1][j-1]+1);//修改a[i]或b[j] } } return f[n][m]; } int main(){ ios::sync_with_stdio(false); int n, m; cin>>n>>m; for(int i = 1; i <= n; i++)cin>>s[i]; for(int i = 1; i <= m; i++){ string t;int k; cin>>t>>k; int ans = 0; for(int i = 1; i <= n; i++) if(dist(s[i], t) <= k)ans++; cout<AcWing 282. 石子合并
#include #include using namespace std; const int maxn = 1010, inf=0xffffff; int w[maxn], f[maxn][maxn]; int main(){ int n; cin>>n; for(int i = 1; i <= n; i++)cin>>w[i]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) f[i][j] = i==j ? 0 : inf; for(int i = 1; i <= n; i++)w[i] += w[i-1]; //转移顺序长度从小到大覆盖即可 for(int i = n; i >= 1; i--)//枚举起点 for(int j = i; j <= n; j++)//枚举终点 for(int k = i; k <= j; k++)//枚举断点 f[i][j] = min(f[i][j],f[i][k]+f[k+1][j]+w[j]-w[i-1]); cout<AcWing 900. 整数划分
//题意:给出一个整数n,求其有多少种形如n==n1+n2+..nk的分法,输出划分总数%1e9+7; //思路:把1,2,3,...,n分别看做n个物体的体积,这n个物体均无使用次数限制,问恰好能装满总体积为n的背包的总方案数(完全背包问题变形)。f[i][j]表示用[1-i]的整数拼成j的方案数,转移时考虑能不能选并把值累加一下就行。 #include using namespace std; const int maxn = 1010; const int mod = 1e9+7; int f[maxn][maxn]; int main(){ ios::sync_with_stdio(false); int n; cin>>n; for(int i = 0; i <= n; i++)f[i][0] = 1;//前i个全不选也是一种方案 for(int i = 1; i <= n; i++){//考虑第i个数选不选 for(int j = 1; j <= n; j++){//能拼成数j的方案数 if(j >= i)f[i][j] = (f[i-1][j]+f[i][j-i])%mod;//能选 else f[i][j] = f[i-1][j]%mod;//不能选 } } cout<AcWing 338. 计数问题
//题意:给出两个数a和b,求a和b之间所有数字中0-9的出现次数,a,b<=1e8 //思路:可以通过找规律推出1-n中数字i出现的次数,然后作差。 #include using namespace std; //计算从1到n的整数中数字i出现多少次 int cal(int n, int i){ int len = 0, t=n; while(t){len++; t/= 10;} //计算位数 int ans = 0; //从右到左第j位上(个十百千),数字i出现多少次 for(int j = 1; j <= len; j++){ //计算第j-1,j,j+1位的数字 int p = pow(10,j-1); int l = n/p/10, r = n%p, dj = n/p%10; //第j位左边的数字小于实际l的情况 if(i)ans += l*p; if(!i && l)ans += (l-1)*p; //第j位左边的数字等于实际l的情况 if((dj>i) && (i||l))ans += p; if((dj==i) && (i||l))ans += r+1; } return ans; } int main(){ ios::sync_with_stdio(false); int a, b; while(cin>>a>>b){ if(a==0 && b==0)break; if(a>b)swap(a,b); for(int i = 0; i <= 9; i++) cout<AcWing 291. 蒙德里安的梦想
/* 题意:把n*m的棋盘分成若干个1*2的长方形,求有多少种方案 思路:首先总的方案数,等价于横着摆放的方案数,所以直接枚举横着的就行。然后如何判断当前方案数是否合法?所有剩余位置能否填充满竖着的小方块。可以按列来看,每一列内部所有连续的空着的小方块需要是偶数个。 状态:f[i][j]表示已经将前i-1列摆好,且从第i−1列,伸出到第i列的状态是j的所有方案,其中j是一个2进制数,表示当前第i列的状态。 状态转移:枚举第(i-1,i)的所有状态j和(i-2,i-1)的所有状态k,如果他们两个不冲突,那就可以从f[i-1,k]转移到f[i,j]。 */ #include using namespace std; typedef long long LL; const int maxn=12; LL ok[1<<12], f[12][1<<12]; int main(){ int n, m; while(cin>>n>>m &&n&&m){ //判断状态i是否合法 for(int i = 0; i < (1<>j)&1==1){ if(cnt%2==1)ok[i]=false; cnt = 0; }else cnt++; } if(cnt%2==1)ok[i] = false; } //dp memset(f,0,sizeof(f)); f[0][0] = 1; for(int i = 1; i <= m; i++){ for(int j = 0; j < (1<AcWing 91. 最短Hamilton路径
//f[i][j]表示当前已经走过点的集合为i,当前人站在j(终点),此时的最短路径长度 //转移时用不包含j的集合向当前集合转移,用集合内的点k和边e[k][j]来更新,f[i][j] = min{f[i][j], f[i-(1< using namespace std; const int maxn=30; int e[maxn][maxn], f[1<<20][maxn]; int main(){ ios::sync_with_stdio(false); int n; cin>>n; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) cin>>e[i][j]; memset(f,0x3f,sizeof(f)); f[1][0] = 0; for(int i = 0; i < (1<>j&1)==1){//j在集合里 for(int k = 0; k < n; k++){ if(((i-(1<>k&1)==1){//走到j这个点之前,以k为终点的最短距离 f[i][j] = min(f[i][j], f[i-(1<AcWing 285. 没有上司的舞会
/* 用f[x][0],f[x][1] 分别表示x没去和去了的最大价值。 f[x][0] = sigmar:max(f[y][0],f[y][1]); f[x][1] = sigmar:f[y][0]; */ #include #include #include #define maxn 6000*2 using namespace std; int n, r[maxn], f[maxn][2], in[maxn]; vectorG[maxn]; void dp(int x){ f[x][1] = r[x]; for(int i = 0; i < G[x].size(); i++){ int y = G[x][i]; dp(y); f[x][0] += max(f[y][0],f[y][1]); f[x][1] += f[y][0]; } } int main(){ cin>>n; for(int i = 1; i <= n; i++)cin>>r[i]; for(int i = 1; i < n; i++){ int a, b; cin>>a>>b; G[b].push_back(a); in[a]++; } int head = 0; //找树根,即入度为0的结点 for(int i = 1; i <= n; i++) if(in[i]==0){ head = i; break; } dp(head); cout<AcWing 901. 滑雪
//f[i][j]:以(i,j)为终点的最长路是是多少 //f[i][j] = f(它四周的比他高的方块的最长路)+1 #include #include using namespace std; const int maxn = 550; int r, c, a[maxn][maxn], f[maxn][maxn], ans; const int dx[] = {1,0,-1,0}; const int dy[] = {0,-1,0,1}; bool inside(int x, int y){return x>=1&&x<=r&&y>=1&&y<=c;} int dp(int x, int y){ if(f[x][y])return f[x][y]; int res = 0; for(int i = 0; i < 4; i++){ int nx = x+dx[i], ny = y+dy[i]; if(inside(nx,ny)&&a[nx][ny]>a[x][y]){ res = max(res,dp(nx,ny)); } } return f[x][y]=res+1;//我竟然因为没有更新f[x][y]导致第二个点没过。。 } int main(){ ios::sync_with_stdio(false); cin>>r>>c; for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) cin>>a[i][j]; for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) ans = max(ans,dp(i,j)); cout<
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。