这一星期做了点背包,主要还是学了下数论gcd,lcm,拓展欧几里得,逆元(没大做题目,只是看了遍,也没有明白书上的例题是怎样利用逆元的),素数和素数筛选的方法,做的题还是不够多,只是对素数筛有点印象,还看了点组合数学,刚开了个头
luogu p4138
排序就按钩数从大到小排,之后就是01背包了,把挂钩数作为容量,并且如果容量小于a[i]的话,就强行认为是1,转移方程为
dp[i][j]=max(dp[i-1][j],dp[i-1][max(j-g[i].a,0)+1]+g[i].b);
P4138 [JOISC2014] 挂饰 题解_cqbzcky的博客-CSDN博客
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int n;
struct gua{
int a,b;
}g[2005];
bool cmp(gua c,gua d){
return c.a>d.a;
}
ll dp[2005][2005],sum=0;
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&g[i].a,&g[i].b),sum+=g[i].a;
sort(g+1,g+1+n,cmp);
ll ans=0;
memset(dp,-inf,sizeof(dp));
dp[0][1]=0;
for(int i=1;i<=n;i++)
for(int j=sum;j>=0;j--)
dp[i][j]=max(dp[i-1][j],dp[i-1][max(j-g[i].a,0)+1]+g[i].b),ans=max(ans,dp[i][j]);
cout<<ans<<endl;
return 0;
}
luogu p4141
按照题目要求的直接来,直接暴力不会超时;还有一种方法是求一遍背包,然后再逆推减去该消失的物品得到答案
洛谷 P4141 消失之物_Red_Sky_ta的博客-CSDN博客
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,v[2005],f[2005];
void bag(){
memset(f,0,sizeof(f));
f[0]=1;
for(int i=1;i<n;i++){
for(int j=m;j>=v[i];j--)
f[j]+=f[j-v[i]],f[j]%=10;
}
}
void print(){
for(int i=1;i<=m;i++) cout<<f[i];
cout<<endl;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<=n;i++){
int tmp=v[i];v[i]=v[n];v[n]=0;
bag();
print();
v[n]=v[i],v[i]=tmp;
}
return 0;
}
luogu p4394
这道题并不是很难,自己却没有想出来,只是在01背包后面加了个判断而已,以后做题还是要多动脑,不然做再多的题也,没用
洛谷P4394 [BOI2008]Elect 选举 题解_ShineEternal的笔记小屋-CSDN博客
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int n,v[310],sum=0,f[100000];
bool cmp(int a,int b){
return a>b;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&v[i]),sum+=v[i];
int ans=0;
sort(v+1,v+n+1,cmp);
for(int i=1;i<=n;i++){
for(int j=sum;j>v[i];j--){
f[j]=max(f[j],f[j-v[i]]+v[i]);
if(f[j]-v[i]<=sum/2&&f[j]>sum/2){
ans=max(ans,f[j]);
}
}
}
cout<<ans<<endl;
return 0;
}
luogu p4823
这道题看了很久才勉强看明白最后的输出,dp[i]代表走i个人后人墙的高度,如果dp[i]>=0说明他参与了转移,说明走i个人是可能的,dp[i]的值的作用也是为了这个
https://lc--fairycastle.blog.luogu.org/solution-p4823
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int n,h;
struct ab{
int a,b;
}c[2005];
bool cmp(ab c,ab d){
return c.a+c.b<d.a+d.b;
}
int dp[2005];
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&n);
memset(dp,-inf,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&c[i].a,&c[i].b);
dp[0]+=c[i].a;
}
scanf("%d",&h);
sort(c+1,c+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=i;j>=1;j--){
if(dp[j-1]+c[i].b>=h)
dp[j]=max(dp[j],dp[j-1]-c[i].a);
}
for(int i=n;i>=0;i--){
if(dp[i]>=0){//dp[i]>0说明他被转移过,说明能走i个人
cout<<i<<endl;
return 0;
}
}
return 0;
}
hdu 5656
统计gcd(a,b)的个数,已知gcd(i1,i2,i3),那么gcd(i1,i2,i3,i4)就是gcd(gcd(i1,i2,i3),i4),用sum[i]来表示gcd的个数,则sum[gcd(i1,i2,i3,i4)]=sum[gcd(i1,i2,i3,i4)]+sum[gcd(i1,i2,i3)],最后把所有gcd相加即可
hdu 5656 递推_HARD_UNDERSTAND-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e8+7;
int t,x,n;
ll sum[1005],ans=0;
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
for(int j=1;j<=1000;j++){
if(sum[j]){
int t=gcd(x,j);
sum[t]=(sum[t]+sum[j])%mod;
}
}
sum[x]++;
}
ans=0;
for(int i=1;i<=1000;i++)
ans=(ans+i*sum[i])%mod;
cout<<ans<<endl;
}
return 0;
}
hdu 5902
题目最后变为进行n-2轮求gcd看看是否有新的gcd出现,进行完从小到大遍历
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e8+7;
int t,n,a[550],vis[1005];
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
int main(){
//freopen("in.txt","r",stdin);
cin>>t;
while(t--){
memset(vis,0,sizeof(vis));
cin>>n;
int flag=1;
int num=n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
vis[gcd(a[i],a[j])]=1;
while(flag&&--num>2){
flag=0;
for(int i=1;i<=1000;i++)
if(vis[i])
for(int j=1;j<=n;j++){
int t=gcd(i,a[j]);
if(!vis[t]) vis[t]=1,flag=1;
}
}
int ca=0;
for(int i=1;i<=1000;i++){
if(vis[i]){
if(ca!=0) cout<<" ";
cout<<i;
ca++;
}
}
cout<<endl;
}
return 0;
}
hdu 2710
看了一个小时也没看出自己到底有啥错误,无奈只能换了种题解的思路,不过题解的思路确实清晰,代码也很简洁
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e4+100;
int prime[maxn],kk;
bool vis[maxn];
void e_sieve(int n){//求每个数的最大素因子
memset(prime,0,sizeof(prime));
prime[1]=1;
for(int i=2;i<=maxn;i++){
if(prime[i]==0){
for(int j=i;j<=20005;j+=i)
prime[j]=i;
}
}
}
int main(){
//freopen("in.txt","r",stdin);
e_sieve(maxn);
prime[0]=1;
int n,x,maxx=0,ma;
while(cin>>n){
maxx=0,ma=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(prime[x]>maxx){
maxx=prime[x];
ma=x;
}
}
cout<<ma<<endl;
}
return 0;
}
牛客 M True Story
True Story |
一个人如果开始行动说明它必定能到达机场,找到最大的时间间隔,看看有多少人能开始行动即可
(5条消息) The 2021 Sichuan Provincial 四川省赛M.True Story(模拟)_jziwjxjd的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
const int inf=0x3f3f3f3f;
const int maxn=1e9;
using namespace std;
int n,k,x,p0,s[100005],t[100005],p[100005];
bool cmp(int a,int b){
return a>b;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d%d%d",&n,&k,&x,&p0);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
for(int i=1;i<=k;i++) scanf("%d",&t[i]);
for(int i=1;i<=k;i++) scanf("%d",&p[i]);
int mx=p0,ans=0;
for(int i=1;i<=k;i++) mx=max(mx,p[i]-t[i]);
for(int i=1;i<=n;i++){
if(1ll*mx*s[i]>=x)
ans++;
}
printf("%d\n",ans);
return 0;
}
hdu3826
n最大是10^18,普通的打表一定会爆,但是可以想一下我们是要判断n是否满足n=p1^2*p2,假设最小素数是p1,那么p1绝不会超过10^6,因为如果超了,那么n就超范围了;然后对1e6的素数打表,然后进行判断,如果n整除了p1,他要是还能再整除一次p1,说明它不是无平方数,return false;如果循环下来n==1,说明他是无平方数 ,如果大于1,说明n有一个素因子是大于1e6的,这样的素因子不可能超过2个,不然就超范围了,所以看看n是不是平方数就行
Squarefree number HDU - 3826(数论)_Coldfresh的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
const int inf=0x3f3f3f3f;
const int maxn=1e9;
using namespace std;
int t;
ll n,k;
int prime[1000005];
bool vis[1000005];
void e_sieve(){
for(int i=0;i<=1000000;i++) vis[i]=false;
for(int i=2;i*i<=1000000;i++)
if(!vis[i])
for(int j=i*i;j<=1000000;j+=i)
vis[j]=true;
k=0;
for(int i=2;i<=1000000;i++)
if(!vis[i])
prime[++k]=i;
}
bool check(ll n){
for(int i=1;i<=k;i++){
if(n%prime[i]==0){
n/=prime[i];
if(n%prime[i]==0)
return false;
}
}
if(n==1) return true;
ll sq=(ll)sqrt(n);
if(sq*sq==n) return false;
else return true;
}
int main(){
//freopen("in.txt","r",stdin);
e_sieve();
scanf("%d",&t);
int ca=1;
while(t--){
scanf("%lld",&n);
printf("Case %d: ",ca++);
if(check(n)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
hdu 6069
HDU 6069 数论 区间素数筛 + 赛后反思_新熊君的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
const int inf=0x3f3f3f3f;
const int maxn=1e6+10;
const int mod=998244353;
using namespace std;
bool vis[maxn];
int pri[maxn],tot;
void init(){//素数打表
tot=0;
for(ll i=2;i<maxn;i++){
if(!vis[i]){pri[++tot]=i;}
for(ll j=1;j<=tot&&i*pri[j]<maxn;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
}
ll ans[maxn],val[maxn];
void solve(ll L,ll R,ll t){
for(ll i=L;i<=R;i++){
ans[i-L]=1;//记录每个数的d(x^k)的值
val[i-L]=i;//记录每个数值
}
for(ll i=1;i<=tot;i++){
ll now=pri[i];//找较大的素数开始除,节省时间
for(ll j=max(2LL,(L+now-1)/now)*now;j<=R;j+=now){
if(val[j-L]%now) continue;
ll cnt=0;
while(val[j-L]%now==0){val[j-L]/=now;cnt++;}
ans[j-L]=(1+t*cnt)%mod*ans[j-L]%mod;
}
}
for(ll i=L;i<=R;i++){
if(val[i-L]>1)//说明还有因子,并且这个因子只出现了一次
ans[i-L]=(1+t)%mod*ans[i-L]%mod;
}
ll sum=0;
for(ll i=L;i<=R;i++)
sum=(sum+ans[i-L])%mod;
printf("%lld\n",sum);
}
int main(){
init();
int t;
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
ll l,r,k;
scanf("%lld%lld%lld",&l,&r,&k);
solve(l,r,k);
}
return 0;
}
牛客 神奇天平
神奇天平 |
这道题很简单啊,每次分成m+1堆,让n除以m向上取整就行,当时一直在想和平方的联系,思路在平方的道路上一去不返。。。
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
int ans=0;
while(n>1){
n=ceil(n*1.0/(m+1));
ans++;
}
printf("%d\n",ans);
}
return 0;
}
牛客 魔法学院(easy)
这道题也是很简单的,当时也没有想出来,在输入m个魔法时就对s串进行调整(这样做不会超时),最后输出s串ASCII码的和就行
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct ma{
int r,l,v;
}a[100005];
bool cmp(ma a,ma b){
return a.v>b.v;
}
char s[100005],c;
int main(){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=m;i++){
scanf("%d%d %c",&a[i].l,&a[i].r,&c);
for(int j=a[i].l;j<=a[i].r;j++)
s[j]=max(s[j],c);
}
int ans=0;
for(int i=1;i<=n;i++) ans+=s[i];
printf("%d\n",ans);
return 0;
}
codeforces C Dominant Character
纯暴力的话必定超时,但想一想情况一共就是有七种: "aa","aba","aca","abca","acba","abbacca","accabba",只要用字符串的find方法找出s串是否含有这七种子串即可,从小的开始搜索以保证字符串长度最小
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s,a[7]={"aa","aba","aca","abca","acba","abbacca","accabba"};
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%d",&n);
cin>>s;
int res=-1;
for(int i=0;i<7;i++){
if(s.find(a[i])!=-1){
res=a[i].size();
break;
}
}
cout<<res<<endl;
}
return 0;
}
poj 2689
区间素数筛的问题,这个可以当做是一个模板了;
poj 2689 Prime Distance 区间素数筛+大数 模板_人生如戏-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000005;
const int N=100005;
ll pri[N],numpri=0,ans[maxn],numans,l,r;
bool vis[N],temp[maxn];
void init(){
vis[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]){
pri[numpri++]=i;
for(int j=i+i;j<=N;j+=i)
vis[j]=1;
}
}
}
void getpri(){
for(ll i=0;i<numpri;i++){
ll b=l/pri[i];
while(b<=1) b++;
for(ll j=b*pri[i];j<=r;j+=pri[i])
if(l<=j)
temp[j-l]=1;
}
if(l==1) temp[0]=1;
}
int main(){
init();
while(~scanf("%lld%lld",&l,&r)){
memset(temp,0,sizeof(temp));
memset(ans,0,sizeof(ans));
numans=0;
getpri();
for(int i=0;i<=r-l;i++){
if(!temp[i])
ans[numans++]=l+i;
}
if(numans<=1){
printf("There are no adjacent primes.\n");
continue;
}
ll mincha=1e9,maxcha=-1e9,minf,mins,maxf,maxs;
for(int i=1;i<numans;i++){
if((ans[i]-ans[i-1])>maxcha){
maxcha=ans[i]-ans[i-1];
maxf=ans[i],maxs=ans[i-1];
}
if(ans[i]-ans[i-1]<mincha){
mincha=ans[i]-ans[i-1];
minf=ans[i],mins=ans[i-1];
}
}
printf("%lld,%lld are closest, %lld,%lld are most distant.\n",mins,minf,maxs,maxf);
}
return 0;
}