洛谷五月赛

第一题:

首先看数据范围,就应该有1000*10000的算法的感觉,就应该考虑依靠这两个条件,做二维循环

欣赏一下login的代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int a[1001],b[1001];
int n,m;

void work(){
    int i,j,t;
    int maxm=b[m],maxn=a[n];
    t=max(maxm,maxn);//
    
    for(i=1;i<=t;i++)//枚举神犇——蒟蒻的循环节长度 
    {
        //memset(c,0,sizeof(c));
        int flag = 0;
        int maxt=0;
        for(j=1;j<=n;j++)
        {
            int tmp=a[j]%i;
            if(tmp==0)
                tmp=i;
            if(tmp>maxt)//求出在这个循环节里,神牛循环占多少节 
                maxt=tmp;
            }

        for(j=1;j<=m;j++)
        {
            int tmp=b[j]%i;
            if(tmp==0)
                tmp=i;
            if(tmp<=maxt)
            {
                flag=1;//如果,当总循环为i时,蒟蒻如果会mod到神牛循环所占的位置的话,
					  //就冲突,更换总循环节长度 
                break;
                }
            }
        if(flag==1)
            continue;
            else
            {
                cout<<maxt<<" "<<i-maxt<<endl;
                return;
                }
        }
    cout<<"NO"<<endl;
    }
int main()
{
    int i;
    while(scanf("%d%d",&n,&m)!=EOF){
        
    for(i=1;i<=n;i++)
        cin>>a[i];

    for(i=1;i<=m;i++)
        cin>>b[i];
    
    sort(a+1,a+1+n);
    sort(b+1,b+1+m);
    
    work();
    
    }
    return 0;
}#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int a[1001],b[1001];
int n,m;

void work(){
    int i,j,t;
    int maxm=b[m],maxn=a[n];
    t=max(maxm,maxn);//
    
    for(i=1;i<=t;i++)//枚举神犇——蒟蒻的循环节长度 
    {
        //memset(c,0,sizeof(c));
        int flag = 0;
        int maxt=0;
        for(j=1;j<=n;j++)
        {
            int tmp=a[j]%i;
            if(tmp==0)
                tmp=i;
            if(tmp>maxt)//求出在这个循环节里,神牛循环占多少节 
                maxt=tmp;
            }

        for(j=1;j<=m;j++)
        {
            int tmp=b[j]%i;
            if(tmp==0)
                tmp=i;
            if(tmp<=maxt)
            {
                flag=1;//如果,当总循环为i时,蒟蒻如果会mod到神牛循环所占的位置的话,
					  //就冲突,更换总循环节长度 
                break;
                }
            }
        if(flag==1)
            continue;
            else
            {
                cout<<maxt<<" "<<i-maxt<<endl;
                return;
                }
        }
    cout<<"NO"<<endl;
    }
int main()
{
    int i;
    while(scanf("%d%d",&n,&m)!=EOF){
        
    for(i=1;i<=n;i++)
        cin>>a[i];

    for(i=1;i<=m;i++)
        cin>>b[i];
    
    sort(a+1,a+1+n);
    sort(b+1,b+1+m);
    
    work();
    
    }
    return 0;
}


第二题:

我刚开始,乘法逆元+位运算+容斥原理+等差数列求和,结果得了70分(代码在上一篇里)好在锻炼了思维

然后………,想用set卡卡试一试,然而,25行代码就a了

醉了,竟然数据没有卡set,smg?

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<set>
#define ll long long
#define mod 376544743
using namespace std;

ll n,m,p[50],ans=0;
int main()
{
	scanf("%lld%lld",&n,&m);
	set<int> s;
	s.clear();
	for (int i=1;i<=n;i++)
	{
		ll x;
		scanf("%lld",&x);
		for (int j=x;j<=m;j+=x) if (!s.count(j))
		{
			s.insert(j);
			ans=(ans+j)%mod; 
		}
	}
	printf("%d",ans);
	return 0;
}

第三题(不会,准备看题解)

好吧做完了发现好像没有那么难,k进制状态压缩,好像并没有加快速度,只是让状态的表示更显然,更好实现了罢了

颠覆了我对状态压缩的理解   复杂度:O(n* k^m * k^m *m) 两个k^m表示枚举两行的状态,m判断是否冲突

前8组,n=50,k<=4,m<=4的情况下(50 * 65536 *4)是可以的 ,以后还是要自己算一下的

最开始觉得很难是觉的这样的暴力过不了,应该是对复杂度分析不够,

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#define mod 376544743
using namespace std;

int n,m,k,s[10009],t[10009],dp[109][65539],ss=0,st=0,S;//dp【n】【S】表示第n行,状态为S,的方案数,这个方案数与上一行状态有直接的关系,即
<span style="white-space:pre">						</span>      //dp【n】【S】=E dp【n-1】【Si】(Si与S不冲突)
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++)scanf("%d",&s[i]),ss=ss*k+s[i];
    for (int i=1;i<=m;i++)scanf("%d",&t[i]),st=st*k+t[i];
    for (int i=1;i<m;i++) if (s[i]==s[i+1]||t[i]==t[i+1]) {printf("0");return 0;}
    if (k==2)
    {
        if ((s[1]==t[1])^(n&1))printf("0");else printf("1");
        return 0;
    }
    S=1;
    for (int i=1;i<=m;i++) S*=k;
    dp[1][ss]=1;
    for (int i=2;i<=n;i++)
    {
        for (int j=1;j<S;j++)//枚举本行所有可行的情况
        {
            int jj=j,tmp[35]={0};
            bool o=true;
            for (int l=1;l<=m;l++) tmp[l]=jj%k,jj/=k;
            for (int l=1;l<m;l++) if (tmp[l]==tmp[l+1]) {o=false;break;}//判断是否可行
            if (!o) continue;
            for (int l=1;l<S;l++)//枚举上一行的状态
            if (dp[i-1][l])
            {
                bool oo=true;
                int tmm[35]={0},kll=l;
                for (int ll=1;ll<=m;ll++) tmm[ll]=kll%k,kll/=k;
                for (int ll=1;ll<m;ll++) if (tmm[ll]==tmm[ll+1]||tmm[ll]==tmp[ll]) {oo=false;break;}//判断是否冲突
                if (!oo||tmm[m]==tmp[m]) continue;
                dp[i][j]=(dp[i][j]+dp[i-1][l])%mod;//累计答案
            }
        }
    }
    printf("%d",dp[n][st]);
    return 0;
}

满分需要轮廓线dp,一步一步学吧

第四题(写了个倍增然后,就没有然后了)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值