2021-11-13(每周总结)

142 篇文章 0 订阅
142 篇文章 1 订阅

        这一星期做了点背包,主要还是学了下数论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)

魔法学院(easy version)

        这道题也是很简单的,当时也没有想出来,在输入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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值