191102-模拟测试11
T1 极好的问题
题目描述
解析
考场上就只打了个30分的暴力
,但其实细想该题的套路还是很明显的,
首先枚举前两个数x,y的乘积,用exgcd求出所需z的值,便可将时间复杂度降至O(n^2),但有一些细节需要注意,比如判重等等(也可以分类讨论,分1,x,y,z都不同;2,两个相同;3,三个相同的情况)
暴力代码
#include<bits/stdc++.h>
using namespace std;
long long n,p,a[5009],ans,m,x,c[5009];
struct zb
{
long long x,y,z;
}b[5000009];
bool comp(const zb &a,const zb &b)
{
if(a.x!=b.x) return a.x<b.x;
if(a.y!=b.y) return a.y<b.y;
return a.z<b.z;
}
int main()
{
freopen("awesome.in","r",stdin);
freopen("awesome.out","w",stdout);
scanf("%lld%lld",&n,&p);
for(int i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
a[i]=c[i]%p;
}
if(n<=100)
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
for(int k=j+1;k<=n;k++)
if((((a[i]*a[j])%p)*a[k])%p==1)
{
ans++;
b[ans].x=min(c[i],min(c[j],c[k]));
b[ans].z=max(c[i],max(c[j],c[k]));
b[ans].y=c[i]+c[j]+c[k]-b[ans].x-b[ans].z;
}
sort(b+1,b+ans+1,comp);
m=ans;
for(int i=1;i<=ans;i++)
if(b[i].x==b[i-1].x&&b[i].y==b[i-1].y&&b[i].z==b[i-1].z)
m--;
printf("%lld",m);
return 0;
}
return 0;
}
题解(照抄std的)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3000+10;
int P;
int fast_pow(int x,int y){
int ret=1;
while (y){
if (y&1) ret=1LL*ret*x%P;
x=1LL*x*x%P;
y>>=1;
}
return ret;
}
struct Number{
int val,inv;
int cnt[4]={0,0,0,0};
} nums[N];
bool cmp_val(const Number& x,const Number& y){
return x.val<y.val;
}
int n,m;
int a[N];
int find(int key){
int l=-1,r=m,mid;
while (l+1<r){
mid=(l+r)>>1;
if (nums[mid].val<key)
l=mid;
else
r=mid;
}
if (r<m&&nums[r].val==key) return r;
return -1;
}
int main(){
scanf("%d%d",&n,&P);
for (int i=0;i<n;++i)
scanf("%d",&a[i]);
sort(a,a+n);
int stamp=0,tmp_cnt=1;
for (int i=1;i<=n;++i){
if (i==n||(i>0&&a[i]!=a[i-1])){
int x=a[i-1]%P,j=0;
if (x>0){
while (j<stamp&&nums[j].val!=x)
++j;
if (j==stamp){
++stamp;
nums[j].val=x;
nums[j].inv=fast_pow(x,P-2);
}
++nums[j].cnt[min(3,tmp_cnt)];
}
tmp_cnt=1;
}
else ++tmp_cnt;
}
m=stamp;
for (int i=0;i<m;++i){
nums[i].cnt[2]+=nums[i].cnt[3];
nums[i].cnt[1]+=nums[i].cnt[2];
// printf("[ num ] %d %d (%d %d %d)\n",nums[i].val,nums[i].inv,nums[i].cnt[1],nums[i].cnt[2],nums[i].cnt[3]);
}
sort(nums,nums+m,cmp_val);
int ans=0;
for (int i=0;i<m;++i)
for (int j=i;j<m;++j){
int need=1LL*nums[i].inv*nums[j].inv%P;
if (i!=j&&(need<=nums[i].val||need<=nums[j].val))
continue;
// if (need<nums[i].val||need<nums[j].val)
// continue;
// if (need==nums[i].val||need==nums[j].val)
// if (nums[i].val!=nums[j].val)
// continue;
int k=find(need);
// printf("%d %d %d\n",i,j,k);
if (k==-1)
continue;
int tmp=0;
if (nums[i].val!=nums[j].val){ // 1,1,1
tmp+=nums[i].cnt[1]*nums[j].cnt[1]*nums[k].cnt[1];
}
else if (nums[i].val!=nums[k].val){ // 2,1
tmp+=nums[i].cnt[1]*(nums[i].cnt[1]-1)/2*nums[k].cnt[1];
tmp+=nums[i].cnt[2]*nums[k].cnt[1];
}
else{ // 3
tmp+=nums[i].cnt[3];
tmp+=nums[i].cnt[2]*(nums[i].cnt[1]-1);
tmp+=1LL*nums[i].cnt[1]*(nums[i].cnt[1]-1)*(nums[i].cnt[1]-2)/6;
}
// if (tmp) printf("%d %d %d\n",nums[i].val,nums[j].val,nums[k].val);
ans+=tmp;
}
printf("%d\n",ans);
return 0;
}
T2 bag
题目描述
解析
考场上想出了正解,但在求最长不下降子序列的时候,只会
的算法,并且有一个细节没有取等,因此只拿了60分。
实际上,该题虽然有背包承重的限制,但我们可以很容易得到一个贪心算法,并且是具有正确性的,首先将物品按照重量升序排序,然后求出其价值的最长不下降子序列,并记录下每次转移的位置(树状数组实现
),然后我们按背包承重上限降序排序,每次二分答案出背包的数量num,自然选取前num个背包自然是最优的,然后判断每个物品对应的背包重量是否小于等于背包承重上限即可
考场代码
#include<bits/stdc++.h>//O(n^2)暴力70
using namespace std;
struct zb
{
int w,val;
}a[100009];
int w[100009],f[100009],g[100009],n,m,T;
int read()
{
int pd=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
pd=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*pd;
}
bool comp(const zb &a,const zb &b)
{
if(a.w!=b.w) return a.w<b.w;
return a.val<b.val;
}
bool cmp(const int &a,const int &b)
{
return a>b;
}
bool check(int r)
{
int vis=0;
for(int i=1;i<=n;i++)
if(f[i]>=r)
{
vis=i;
break;
}
if(!vis) return false;
int cnt=1;
bool bj=0;
while(vis)
{
if(a[vis].w>w[cnt]){//注意不取等
bj=1;
break;
}
vis=g[vis];
cnt++;
}
if(bj) return false;
return true;
}
int main()
{
freopen("bag1.in","r",stdin);
//freopen("bag.out","w",stdout);
T=read();
while(T--)
{
memset(a,0,sizeof(a));
memset(w,0,sizeof(w));
n=read();
for(int i=1;i<=n;i++)
{
a[i].w=read();
a[i].val=read();
}
sort(a+1,a+n+1,comp);
m=read();
for(int i=1;i<=m;i++)
w[i]=read();
sort(w+1,w+m+1,cmp);
for(int i=1;i<=n;i++)
{
g[i]=0;
f[i]=1;
}
for(int i=1;i<=n;i++)
{
int vis=0;
int maxx=0;
for(int j=i-1;j>=1;j--)
if(a[i].val>=a[j].val)//注意取等
if(f[j]>=maxx)//注意取等
{
maxx=f[j];
vis=j;
}
f[i]+=maxx;
g[i]=vis;
}
for(int i=1;i<=n;i++)
printf("%d %d\n",f[i],g[i]);
int l=1;
int r=m;
while(l<r)
{
int mid=(1+l+r)>>1;
if(check(mid))
l=mid;
else
r=mid-1;
}
printf("%d\n",l);
}
return 0;
}
正解(照抄std)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
int n;
const int N=int(1e5)+10;
template<typename T>
struct BIT{
T c[N];
static int lowbit(int x){return x&-x;}
void clear(){memset(c,0,sizeof(c));}
void modify(int pos,T val){
for (int i=pos;i<=n;i+=lowbit(i))
c[i]=max(c[i],val);
}
T query(int pos){
T ret=T();
for (int i=pos;i;i-=lowbit(i))
ret=max(ret,c[i]);
return ret;
}
};
BIT<int> bit;
int m;
pii item[N]; // first->weight ; second->value
#define weight first
#define value second
pii temp[N];
int bag[N];
void work(){
scanf("%d",&n);
for (int i=1;i<=n;++i){
int w,v;
scanf("%d%d",&w,&v);
item[i]=make_pair(w,v);
}
sort(item+1,item+n+1);
for (int i=1;i<=n;++i)
temp[i]=make_pair(item[i].value,i);
sort(temp+1,temp+n+1,greater<pii>());
int stamp=0;
for (int i=1;i<=n;++i){
if (i==1||temp[i].first!=temp[i-1].first)
++stamp;
item[temp[i].second].value=stamp;
}
scanf("%d",&m);
for (int i=1;i<=m;++i){
scanf("%d",&bag[i]);
}
sort(bag+1,bag+m+1,greater<int>());
int p=0;
bit.clear();
int ans=0;
for (int i=n;i>0;--i){
while (p<m&&bag[p+1]>=item[i].weight) ++p;
int res=bit.query(item[i].value);
int nxt=min(res+1,p);
bit.modify(item[i].value,nxt);
ans=max(ans,nxt);
}
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
work();
}
return 0;
}
附上我自己写的假正解(每次会wa三个点)
#include<bits/stdc++.h>
using namespace std;
struct zb
{
int w,val;
}a[1000009];
struct qrx
{
int x,y;
}tree[3000009];
int w[1000009],f[1000009],g[1000009],n,m,T,len,c[1000009];
int read()
{
int pd=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
pd=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*pd;
}
bool comp(zb a,zb b)
{
if(a.w!=b.w) return a.w<b.w;
return a.val<b.val;
}
bool cmp(int a,int b) {return a>b;}
int lowbit(int i) {return i&(-i);}
void update(int x,int y,int num)
{
while(x<=len+1)
{
if(tree[x].x<y)
{
tree[x].x=y;
tree[x].y=num;
}
x+=lowbit(x);
}
}
qrx query(int x)
{
qrx sum={0,0};
while(x>0)
{
if(sum.x==tree[x].x)
sum.y=min(sum.y,tree[x].y);
if(sum.x<tree[x].x)
{
sum.x=tree[x].x;
sum.y=tree[x].y;
}
x-=lowbit(x);
}
return sum;
}
bool check(int r)
{
int vis=0;
for(int i=1;i<=n;i++)
if(f[i]>=r)
{
vis=i;
break;
}
if(!vis) return false;
int cnt=1;
bool bj=0;
while(vis)
{
if(a[vis].w>w[cnt]){//注意不取等
bj=1;
break;
}
vis=g[vis];
cnt++;
}
if(bj) return 0;
return 1;
}
int main()
{
freopen("bag2.in","r",stdin);
// freopen("bag.out","w",stdout);
T=read();
while(T--)
{
memset(tree,0,sizeof(tree));
memset(c,0,sizeof(c));
memset(a,0,sizeof(a));
memset(w,0,sizeof(w));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
n=read();
for(int i=1;i<=n;i++)
{
a[i].w=read();
a[i].val=read();
c[i]=a[i].val;
}
sort(a+1,a+n+1,comp);
sort(c+1,c+n+1);
len=unique(c+1,c+n+1)-c-1;
m=read();
for(int i=1;i<=m;i++)
w[i]=read();
sort(w+1,w+m+1,cmp);
for(int i=1;i<=n;i++)
{
a[i].val=lower_bound(c+1,c+len+1,a[i].val)-c;
qrx tmp=query(a[i].val);
tmp.x+=1;
f[i]=tmp.x;
g[i]=tmp.y;
update(a[i].val,tmp.x,i);
//printf("%d %d %d %d\n",f[i],g[i],a[i].val,a[i].w);
}
int l=1;
int r=m;
while(l<r)
{
int mid=(1+l+r)>>1;
if(check(mid))
l=mid;
else
r=mid-1;
}
printf("%d\n",l);
}
return 0;
}
T3 子树问题
题目描述
解析
考场上写的dfs暴力拿了28分,正解是计数类dp(着实不会 )
就先放篇题解吧 传送门
考场代码
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,k,l,r,ans,depth,a[10009],dep[30000],size[10009],fa[10009],vis[10009],x;
int read()
{
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
void getfa(int r,int add)
{
size[r]+=add;
if(fa[r]==r) return;
getfa(fa[r],add);
}
void dfs1(int u)
{
if(dep[u]>depth)
return;
if(u==n)
{
bool bj=0;
for(int j=1;j<=n;j++)
if(vis[size[j]])
return;
for(int j=1;j<=n;j++)
if(dep[j]==depth)
{
bj=1;
break;
}
if(bj)
{
ans++;
ans%=mod;
}
return;
}
for(int i=1;i<=u;i++)
{
dep[u+1]=dep[i]+1;
fa[u+1]=i;
getfa(u+1,1);
dfs1(u+1);
getfa(u+1,-1);
}
}
void dfs2(int u)
{
if(dep[u]>depth)
return;
if(u==n)
{
bool bj=0;
for(int j=1;j<=n;j++)
if(dep[j]==depth)
{
bj=1;
break;
}
if(bj)
{
ans++;
ans%=mod;
}
return;
}
for(int i=1;i<=u;i++)
{
dep[u+1]=dep[i]+1;
dfs2(u+1);
}
}
int main()
{
freopen("subtree.in","r",stdin);
freopen("subtree.out","w",stdout);
n=read();
k=read();
for(int i=1;i<=k;i++)
{
x=read();
vis[x]=1;
}
l=read();
r=read();
if(vis[n])
{
for(int i=l;i<=r;i++)
printf("0 ");
return 0;
}
if(k!=0)
{
for(int i=l;i<=r;i++)
{
depth=i;
if(i==1)
{
printf("0 ");
continue;
}
if(i==2)
{
if(vis[1])
printf("0 ");
else
printf("1 ");
continue;
}
memset(size,0,sizeof(size));
memset(fa,0,sizeof(fa));
memset(dep,0,sizeof(dep));
ans=0;
fa[1]=1;
fa[2]=1;
size[1]=2;
size[2]=1;
dep[1]=1;
dep[2]=2;
dfs1(2);
printf("%d ",ans%mod);
}
return 0;
}
if(!k)
{
for(int i=l;i<=r;i++)
{
depth=i;
if(i==1)
{
printf("0 ");
continue;
}
if(i==2)
{
if(vis[1])
printf("0 ");
else
printf("1 ");
continue;
}
memset(dep,0,sizeof(dep));
ans=0;
dep[1]=1;
dep[2]=2;
dfs2(2);
printf("%d ",ans%mod);
}
return 0;
}
return 0;
}
题解(照抄std)
#include <bits/stdc++.h>
using namespace std;
const int P=998244353;
const int N=500+10;
int c[N][N];
int n;
int dp[N][N];
bool ban[N];
int main(){
int k;
scanf("%d%d\n",&n,&k);
memset(c,0,sizeof(c));
for (int i=0;i<=n;++i){
c[i][0]=1;
for (int j=1;j<=i;++j)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
}
memset(ban,0,sizeof(ban));
for (int i=1;i<=k;++i){
int x;
scanf("%d",&x);
ban[x]=1;
}
memset(dp,0,sizeof(dp));
dp[1][1]=ban[1]?0:1;
for (int d=2;d<=n;++d){
for (int i=1;i<=n;++i){
if (i==1){
dp[i][d]=1;
continue;
}
for (int j=1;j<i;++j){
dp[i][d]=(dp[i][d]+1LL*dp[i-j][d]*dp[j][d-1]%P*c[i-2][j-1])%P;
}
// printf("dp[%d][%d]=%d\n",i,d,dp[i][d]);
}
for (int i=1;i<=n;++i)
if (ban[i])
dp[i][d]=0;
}
int L,R;
scanf("%d%d",&L,&R);
for (int i=L;i<=R;++i){
printf("%d",(dp[n][i]-dp[n][i-1]+P)%P);
if (i!=R) putchar(' ');
}
puts("");
return 0;
}