第一题:
首先看数据范围,就应该有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,一步一步学吧
第四题(写了个倍增然后,就没有然后了)