![这里写图片描述](https://img-blog.csdn.net/20161106152547365)
【问题描述】
从1−n中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数
最大可能是多少。
【输入格式】
第一行一个数字n。
【输出格式】
一行一个整数代表答案对100000007取模之后的答案。
【样例输入】
7
【样例输出】
144
【样例解释】
但是塔外面有东西。
【数据规模与约定】
对于20%的数据,1<=n<=100。;
对于50%的数据,1<=n<=5000;
对于70%的数据,1<=n<=10^5;
对于100%的数据,1≤ n≤ 5*10^6;
思路
质因数分解,在1-n范围内的因数,偶数次幂的因数相乘,奇数次幂的因数的幂减一在相乘,得出的数就是ans
例如样例:
n=7,从2、3、4、5、6、7中选数
2=2^1;
3=3^1;
4=2^2;
5=5^1;
6=2^1*3^1;
7=7^1;
所以质因数2的幂是4,3的幂是2;
ans=2^4*3^2==144;
代码
using namespace std;
ll prime[MAXN],tot,c[MAXN],n,ans=1;
bool b[MAXN];
inline void read(ll&x) {
ll f=1;x=0;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();
x=x*f;
}
inline void prim() {
for(int i=2;i<=MAXN;i++) {
if(!b[i]) prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=MAXN;j++) {
b[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
inline void ff() {
for(int i=1;i<=tot;i++) {
ll p=prime[i];
if(p>n) break;
while(n>=p)
c[i]+=n/p,p*=prime[i];
}
}
inline ll quick_pow(ll a,ll b) {
ll cnt=1;
while(b) {
if(b&1) cnt=(a*cnt)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return cnt%MOD;
}
int main() {
freopen("hao.in","r",stdin);
freopen("hao.out","w",stdout);
read(n);
prim();
ff();
for(int i=1;i<=tot;i++)
if(c[i]&1) c[i]--;
for(int i=1;i<=tot;i++) {
if(prime[i]>n) break;
ans=(ans*quick_pow(prime[i],c[i]))%MOD;
}
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
![这里写图片描述](https://img-blog.csdn.net/20161106152618834)
【问题描述】
有n个数,随机选择一段区间,如果这段区间的所有数的平均值在[?,?]中则
你比较厉害。求你比较厉害的概率。
【输入格式】
第一行有三个数n,l,r,含义如上描述。
接下来一行有n个数代表每一个数的值。
【输出格式】
输出一行一个分数 a/b代表答案,其中a,b互质。如果答案为整数则直接输出该
整数即可。
【样例输入 1】
4 2 3
3 1 2 4
【样例输出 1】
7/10
【样例输入 2】
4 1 4
3 1 2 4
【样例输出 2】
1
【样例解释】
塔外面有棵树。
【数据规模与约定】
对于30%的数据,1<=n<=10^4;
对于60%的数据,1≤n≤10^5 。
对于100%的数据,1 ≤n≤5*10^5 ,0<l≤r≤100。
思路:
此题乍一看,一脸懵逼,zhx讲后,原来是逆序对0.0.......
证明:
平均数=(ai+1,ai+2..ai+n)/n
观察发现 ai数组 记前n项和(即a1+a2+a3..+an)为 An
那么要使平均数在 [l,r]内 那么 n*l<=An<=n*r
于是在区间[al,ar]中同时减去l,如果[al,ar]的和小于零,
则平均数不在[al,ar]内,大于零就在范围内。
同理[al,ar]区间减去r大于零就在范围内
(为什么可以这样大家自己YY一下就好了,还是比较显然的)
所以可以分别求一下ai数组减去 l和r 后前缀和,记为Si
当减去l时,如果Sb-Sa>0那么说明区间[a,b]的平均数在[l,r]内
变形可以得到Sb>Sa
then于是逆序对就出来了.......T_T
当是减去r时正好相反,那么将sum反转一下就和减去l的情况一样了
真是太神辣!!
还要说一点就是这里用了补集转化的思想
我们求得是逆序对,可以发现逆序对是不合法的情况,
那么用总的情况减去不合法的情况就是合法情况了
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int a[500100],b[500100],l,r,n;
LL sum[500100],c[500100],zi,mu,ans;
LL gcd(LL x,LL y)
{
if(x<y)swap(x,y);
return (!y)?x:gcd(y,x%y);
}
void merge(int l,int mid,int r)
{
int i=l,j=mid,k=l-1;
while((i<=mid-1)&&(j<=r))
{
if(sum[j]<sum[i])ans+=(LL)(mid-1-i+1);
if(sum[j]<sum[i])c[++k]=sum[j++];
else c[++k]=sum[i++];
}
while(i<=mid-1)c[++k]=sum[i++];
while(j<=r)c[++k]=sum[j++];
for(i=l;i<=r;i++)sum[i]=c[i];
}
void gb(int l,int r)
{
if(l==r)return;
int mid=(l+r)>>1;
gb(l,mid);gb(mid+1,r);
merge(l,mid+1,r);
}
int main()
{
freopen("jian.in","r",stdin);
freopen("jian.out","w",stdout);
int i,j,k;
scanf("%d%d%d",&n,&l,&r);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++) b[i]=a[i]-l;
for(i=1;i<=n+1;i++) sum[i]=sum[i-1]+b[i-1];
ans=0;gb(1,n+1);
zi+=ans;
memset(sum,0,sizeof(sum));
for(i=1;i<=n;i++) b[i]=a[i]-r;
for(i=1;i<=n+1;i++) sum[i]=sum[i-1]+b[i-1];
reverse(sum+1,sum+n+2);
ans=0;gb(1,n+1);
zi+=ans;
mu=(LL)n*(LL)(n+1)/2;zi=mu-zi;
if(zi==0)printf("0\n");
else if(zi==mu)printf("1\n");
else
{
LL d=gcd(zi,mu);
zi/=d;mu/=d;
cout<<zi<<'/'<<mu<<endl;
}
return 0;
}
![这里写图片描述](https://img-blog.csdn.net/20161106174801052)
【问题描述】
m×m的方阵上有n棵葱,你要修一些栅栏把它们围起来。一个栅栏是一段
沿着网格建造的封闭图形(即要围成一圈)。各个栅栏之间应该不相交、不重叠
且互相不包含。如果你最多修k个栅栏,那么所有栅栏的长度之和最小是多少?
【输入格式】
第一行三个整数m,k,n;
接下来n行每行两个整数x,y代表某棵葱的位置。
【输出格式】
一行一个整数代表答案。
【样例输入 1】
6 1 4
1 3
4 2
4 4
6 4
【样例输出 1】
18
【样例输入 2】
6 2 4
1 3
4 2
4 4
6 4
【样例输出 2】
16
【样例解释】
你猜树上有啥。
【数据规模与约定】
对于10%的数据,k=1。
对于30%的数据,k<=2;
对于60%的数据,k≤ 10。
对于100%的数据,1 ≤k≤n≤ 16,m≤ 1000。
思路:
思路是没有思路0.0
只有纯搜索
加卡时也只能搜到95分 没想到更好的方法
代码
#include<cstdio>
#include<iostream>
#include<ctime>
#include<cstring>
#include<cstdlib>
#define N 25
#define INF 1000000000
using namespace std;
int m,k,n,x[N],y[N],a[N],mnx[N],mxx[N],mny[N],mxy[N],ans=INF;
void dfs(int t)
{
if(clock()>=1950)
{
printf("%d",ans);exit(0);
}
if(t>n)
{
int sum=0;
for(int i=1;i<=k;i++)
if(a[i])sum+=(mxx[i]-mnx[i]+mxy[i]-mny[i]+2)*2;
ans=min(ans,sum);
return;
}
int sum=0;
for(int i=1;i<=k;i++)
if(a[i])sum+=(mxx[i]-mnx[i]+mxy[i]-mny[i]+2)*2;
if(sum>=ans)return;
for(int i=1;i<=k;i++)
{
int pmnx=mnx[i],pmxx=mxx[i],pmny=mny[i],pmxy=mxy[i];
mnx[i]=min(mnx[i],x[t]);mxx[i]=max(mxx[i],x[t]);
mny[i]=min(mny[i],y[t]);mxy[i]=max(mxy[i],y[t]);
a[i]++;
dfs(t+1);
mnx[i]=pmnx,mxx[i]=pmxx,mny[i]=pmny,mxy[i]=pmxy;
a[i]--;
}
}
int main()
{
memset(mnx,0x3f3f3f3f,sizeof(mnx));
memset(mny,0x3f3f3f3f,sizeof(mny));
scanf("%d%d%d",&m,&k,&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
dfs(1);
printf("%d",ans);
fclose(stdin);fclose(stdout);
return 0;
}