西安铁一中2018暑期集训第二期模拟赛DAY2题解
T1:大家都会,推规律就行。
T2:工资
- 题意:求
n
以内与
n
互质的数的四次方和。
(n≤108)
- 题解:质因数分解+容斥原理。
- 本题需要一定的数学基础:1~n的四次方和公式:
-
n(n+1)(2n+1)(3n2+3n−1)/30
。证明略。
- 有了这个公式,我们就可以求出与
n
不互质的数的个数,因此可以将n分解质因数,所有含质因数的倍数的数的四次方和显然可以提出最小的那个数作为公因式,然后用四次方和公式即可。
- 利用容斥原理去重即可。注意
n=1
时的答案是0。
- 代码:
using namespace std;
typedef long long LL;
LL read()
{
char c=getchar();LL f=1,sum=0;
while(c<'0' || c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
int T;
LL n,inv=233333335LL;
LL sqrsqr(LL x){return x*x%mod*x%mod*x%mod;}
LL cal(LL n){return n*(n+1)%mod*(2*n+1)%mod*((3*n*n%mod+3*n-1)%mod)%mod*inv%mod;}
int prime[1005],tot;
void pri(LL x)
{
tot=0;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
prime[tot++]=i;
while(x%i==0) x/=i;
}
}
if(x>1) prime[tot++]=x;
}
void solve()
{
LL sum=0;
for(int i=1;i<(1<<tot);i++)
{
LL v=1;int num=0;
for(int j=0;j<tot;j++)
{
if(i&(1<<j))
num++,v=v*prime[j]%mod;
}
LL t=cal(n/v);
v=sqrsqr(v)*t;
if(num&1) sum=(sum+v)%mod;
else sum=(sum-v)%mod;
}
printf("%lld\n",(cal(n)-sum+mod)%mod);
}
int main()
{
freopen("salary.in","r",stdin);
freopen("salary.out","w",stdout);
T=read();
while(T--)
{
n=read();
if(n==1)
{
puts("0");
continue;
}
pri(n);
solve();
}
return 0;
}
T3:按钮
- 题意:懒得写了。
- 题解:首先能发现几个结论:
- 因为一个格子只能被刷一遍,所以只能先把所有按钮所在的地方的格子分别刷一遍,当然如果不需要刷就不刷。
- 夹在两个按钮之间的,我们肯定不会刷这两个按钮之间的地方,因为直接刷这一行或这一列肯定会更优。
- 因为要求按钮键间距都相同,那么按钮的大小肯定不会很多,枚举是可行的。
- 通过以上结论,我们可以确定我们的步骤:
- 1、枚举按钮的大小,并且暴力刷按钮。
- 2、因为直接建立二分图会造成点数爆炸,因此我们可以暴力把按钮之间的全部刷掉,然后建立二分图,这样点数就从r*c减小到r+c,不会超时。
- 至于为什么要用二分图:对不处于按钮之间,且需要刷的点,要么被行刷掉,要么被列刷掉,这就是网格图上的最小点覆盖模型,因此对行与列之间连边,跑出来的最大匹配数就是答案。
- 代码:
#include<bits/stdc++.h>
#define maxn 100005
#define inf (1<<30)
#define mod 1000000007
using namespace std;
typedef long long LL;
LL read()
{
char c=getchar();LL f=1,sum=0;
while(c<'0' || c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
LL ans,tans;
int R,C,r,c,t,cnt=0;
bool mp[2050][2050],col[2050][2050],vis[1000];
int head[1000],nex[1000],to[1000],match[1000];
char s[5000];
void add(int u,int v)
{
to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}
bool dfs(int x)
{
for(int i=head[x];i;i=nex[i])
{
if(!vis[to[i]])
{
vis[to[i]]=1;
if(!match[to[i]]||dfs(match[to[i]]))
{
match[to[i]]=x;
return true;
}
}
}
return false;
}
void init()
{
cnt=0,tans=inf;
memset(mp,0,sizeof(mp));
memset(col,0,sizeof(col));
memset(head,0,sizeof(head));
memset(match,0,sizeof(match));
}
int main()
{
while(scanf("%d%d%d%d%d",&R,&C,&r,&c,&t)!=EOF)
{
init();
for(int i=1;i<=R;i++)
{
scanf("%s",s+1);
for(int j=1;j<=C;j++)
mp[i][j]=1^int(s[j]-'0');
}
int x=1,flag=0;
for(;x*r<=R&&x*c<=C;x++)
{
int cha1=R-r*x,cha2=C-c*x;
if(cha1%(r+1)!=0) continue;
else if(cha2%(c+1)!=0) continue;
int dis1=(R-r*x)/(r+1),dis2=(C-c*x)/(c+1);
if(dis1!=dis2)continue;
if(dis1>x)continue;
if(!dis1)continue;
ans=0,flag=1;
for(int i=dis1+1;i<=R;i+=dis1+x)
for(int j=dis2+1;j<=C;j+=dis2+x)
{
int f=0;
for(int ii=i;ii<=i+x-1;ii++)
{
if(f)break;
for(int jj=j;jj<=j+x-1;jj++)
if(mp[ii][jj]){f=1;ans+=t;break;}
}
}
for(int i=0;i<=r;i++)
for(int j=0;j<=c;j++)
{
int si=i*(x+dis1)+1;
int sj=j*(x+dis1)+1;
for(int ii=si;ii<=si+dis1-1;ii++)
{
if(col[i][j])break;
for(int jj=sj;jj<=sj+dis2-1;jj++)
if(!mp[ii][jj])
{
col[i][j]=1;
break;
}
}
}
for(int i=0;i<=r;i++)
for(int j=0;j<c;j++)
{
int si=i*(x+dis1)+1;
int sj=j*(x+dis1)+dis1+1;
int f=0;
for(int ii=si;ii<=si+dis1-1;ii++)
{
if(f)break;
for(int jj=sj;jj<=sj+x-1;jj++)
if(!mp[ii][jj])
{
f=1;ans+=t;
for(int k=0;k<=c;k++)
col[i][k]=0;
break;
}
}
if(f)break;
}
for(int j=0;j<=c;j++)
for(int i=0;i<r;i++)
{
int si=i*(x+dis1)+dis1+1;
int sj=j*(x+dis1)+1;
int f=0;
for(int ii=si;ii<=si+x-1;ii++)
{
if(f)break;
for(int jj=sj;jj<=sj+dis1-1;jj++)
if(!mp[ii][jj])
{
f=1;
ans+=t;
for(int k=0;k<=r;k++)
col[k][j]=0;
break;
}
}
if(f)break;
}
for(int i=0;i<=r;i++)
for(int j=0;j<=c;j++)
if(col[i][j])
add(i+1,j+1);
for(int i=1;i<=r+1;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans+=t;
}
tans=min(tans,ans);
}
if(!flag)
puts("-1");
else printf("%lld\n",tans);
}
}