POJ3006
数据范围1e6,所以直接线性筛把素数筛出来就可以了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
ll isprime[maxn],prime[maxn];
ll f[maxn];
int cnt = 0;
void getprime()
{
memset(isprime,1,sizeof(isprime));
isprime[0] = isprime[1] = 0;
for(int i=2;i<maxn;i++)
{
if(isprime[i])
{
prime[++cnt] = i;
}
for(int j=1;j<=cnt && i*prime[j]<maxn;j++)
{
isprime[i*prime[j]] = 0;
if(i%prime[j]==0) break;
}
}
memset(isprime,0,sizeof(isprime));
for(int i=1;i<=cnt;i++)
{
isprime[prime[i]] = 1;
}
}
int main()
{
int a,d,n;
getprime();
while(~scanf("%d%d%d",&a,&d,&n))
{
if(a==0 && d==0 && n==0) break;
ll sum = a;
int tmp = n;
while(tmp)
{
if(isprime[sum]) tmp--;
sum += d;
}
printf("%lld\n",sum-d);
}
return 0;
}
POJ2181
动态规划
dp[i][1]表示上一次是加上权值,dp[i][0]表示上一次减掉权值。
则dp[i][1]要么不变,要么减掉权值,dp[i][0]要么不变,要么加上权值。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 2e5+7;
int a[maxn];
int dp[maxn][2];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
dp[1][0] = a[1];
for(int i=2;i<=n;i++)
{
dp[i][1] = max(dp[i-1][1],dp[i-1][0]-a[i]);
dp[i][0] = max(dp[i-1][0],dp[i-1][1]+a[i]);
}
cout<<max(dp[n][1],dp[n][0])<<endl;
return 0;
}
POJ2385
dp[i][j][k]表示前i分钟,已经移动了j次,当前在k树下的最大值。
那么对于一个状态,要么是移动,要么不移动,然后更新一下最大值就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1010;
int dp[maxn][35][3];
int a[maxn];
int main()
{
int t,w;
cin>>t>>w;
for(int i=1;i<=t;i++)
{
cin>>a[i];
}
if(a[1]==1)
{
dp[1][0][1] = 1;
}
else
{
dp[1][0][2] = 1;
}
int ans = 0;
for(int i=2;i<=t;i++)
{
if(a[i]==1)
{
dp[i][0][1] = dp[i-1][0][1]+1;
dp[i][0][2] = dp[i-1][0][2];
}
else
{
dp[i][0][1] = dp[i-1][0][1];
dp[i][0][2] = dp[i-1][0][2]+1;
}
for(int j=1;j<=w;j++)
{
if(a[i]==1)
{
dp[i][j][1] = max(dp[i-1][j][1]+1,dp[i-1][j-1][2]+1);
dp[i][j][2] = dp[i-1][j][2];
}
else
{
dp[i][j][2] = max(dp[i-1][j][2]+1,dp[i-1][j-1][1]+1);
dp[i][j][1] = dp[i-1][j][1];
}
ans = max(ans,max(dp[i][j][1],dp[i][j][2]));
}
}
printf("%d\n",ans);
return 0;
}
POJ1159
由于我们可以在任意位置插入字符,我们就直接求出本来串的最大回文长度,答案是len-dp[len][len]。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 5010;
int dp[2][maxn];
int main()
{
int n;
cin>>n;
string s;
cin>>s;
string p = s;
reverse(s.rbegin(),s.rend());
s.insert(0,"&");
p.insert(0,"#");
for(int i=1;i<s.size();i++)
{
for(int j=1;j<p.size();j++)
{
if(s[i]==p[j])
{
dp[i%2][j] = dp[(i-1)%2][j-1]+1;
}
else
{
dp[i%2][j] = max(dp[i%2][j-1],dp[(i-1)%2][j]);
}
}
}
cout<<s.size()-1-dp[(s.size()-1)%2][p.size()-1]<<endl;
return 0;
}
POJ1050
我们要求最大子矩阵,是个二维的问题。我们就对每行求最大子序列,然后枚举列,就可以更新出一个矩阵的最大值了。
#include <iostream>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 200;
int a[maxn][maxn];
int sum[maxn][maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
sum[i][j] = sum[i][j-1]+a[i][j];
}
}
int ans = -INF;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int tmp = 0;
for(int k=1;k<=n;k++)
{
tmp += sum[k][j]-sum[k][i-1];
if(tmp<0)
{
tmp = 0;
}
ans = max(ans,tmp);
}
}
}
cout<<ans<<endl;
return 0;
}
POJ2378
树形dp裸题,dp[i]表示以i为根节点的左右子树中最大的节点数,那么显然如果最大的子树都小于等于(n/2),那么所有的都满足条件了。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1e5+7;
vector<int> G[maxn];
int dp[maxn];
int size[maxn];
int n;
void dfs(int now,int fa)
{
size[now] = 1;
dp[now] = 1;
for(int i=0;i<G[now].size();i++)
{
int v = G[now][i];
if(v!=fa)
{
dfs(v,now);
size[now] += size[v];
dp[now] = max(dp[now],size[v]);
}
}
dp[now] = max(dp[now],n-size[now]);
}
int main()
{
scanf("%d",&n);
int x,y;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,0);
for(int i=1;i<=n;i++)
{
if(dp[i]<=n/2) cout<<i<<endl;
}
return 0;
}
CF1088E
和上一题很相似,不过这个题目需要记录一下最大值的数目,跑两次dfs即可。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 3e5+7;
typedef long long ll;
vector<int> G[maxn];
ll v[maxn];
int n;
ll size[maxn];
ll dp[maxn];
ll ans = -INF;
int cnt = 0;
void dfs(int now,int fa)
{
dp[now] = v[now];
for(int i=0;i<G[now].size();i++)
{
int v = G[now][i];
if(v!=fa)
{
dfs(v,now);
if(dp[v]>0) dp[now] += dp[v];
}
}
ans = max(ans,dp[now]);
}
void dfs2(int now,int fa)
{
dp[now] = v[now];
for(int i=0;i<G[now].size();i++)
{
int v = G[now][i];
if(v!=fa)
{
dfs2(v,now);
if(dp[v]>0) dp[now] += dp[v];
}
}
if(dp[now]==ans)
{
cnt++;
dp[now] = 0;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",v+i);
}
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x].pb(y);
G[y].pb(x);
}
dfs(1,0);
dfs2(1,0);
cout<<ans*cnt<<" "<<cnt<<endl;
return 0;
}