B - C HDU - 6025
题意:给你一个最大公约数为1的序列,选择其中一个去掉,使得剩余序列最大公约数最大。输出最大公约数
思路:一开始想的暴力,两重循环,结果一看数据范围,肯定会超时。然后就想怎么能让它简化一重循环?其实就是从前往后一次记录每个位置的前缀最大公约数,然后在从后往前求每个位置的后缀最大公约数,然后再根据每个位置,利用其前缀最大公约数和后缀最大公约数求最大公约数,这样就简化成一重循环。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define M 100005
#define inf 0x3f3f3f3f
int ans;
int n,a[M],b[M],c[M];
int gcd(int a,int b)
{
return b==0? a : gcd(b,a%b);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
a[0]=a[n];
a[n+1]=a[1];
b[1] = a[1]; ///qianmian
c[n] = a[n]; ///houmian
for(int i=1;i<=n;i++) b[i] = gcd( b[i-1] , a[i]);
for(int j=n;j>=1;j--) c[j] = gcd(c[j+1],a[j]);
ans = -inf;
for(int i=1;i<=n;i++)
{
ans = max(ans,gcd(b[i-1],c[i+1]));
}
printf("%d\n",ans);
}
return 0;
}
D - E HDU - 6027
题意:
求1-n中每个数的k次方的和,n到10000,用普通方法肯定不行,这里用到快速幂取模
代码:
#include <bits/stdc++.h>
using namespace std;
const long long mod = 1e9+7;
long long quickmi(long long a, long long b){
long long ans = 1;
a %= mod;
while(b){
if( b & 1 ) ans = (ans*a) % mod;
b >>= 1;
a = (a*a) % mod;
}
return ans;
}
int main()
{
int t;
long long n,k;
cin>>t;
while(t--){
cin>>n>>k;
long long sum = 0;
for( long long i = 1; i <= n; i++ )
sum = (sum + quickmi(i, k)) % mod;
cout<<sum%mod<<endl;
}
return 0;
}
未完待续--------------------------
F - G HDU - 6029
题意:
给定图的 n 个顶点以及 a2,a3,...,an 。其中 ai(1≤ai≤2)表示其在图中与其它点的关系:
1 点 i 与所有标号小于 i 的点均存在一条边。
2 点 i 与所有标号小于 i 的点都不存在边。
perfect matching 被定义为图中存在一个边集,使得所有顶点有且仅有一条边与之相连。
问对于给定的图,是否存在 perfect matching ?
思维题,代码如下:
题意:
给定图的 n 个顶点以及 a2,a3,...,an 。其中 ai(1≤ai≤2)表示其在图中与其它点的关系:
1 点 i 与所有标号小于 i 的点均存在一条边。
2 点 i 与所有标号小于 i 的点都不存在边。
perfect matching 被定义为图中存在一个边集,使得所有顶点有且仅有一条边与之相连。
问对于给定的图,是否存在 perfect matching ?
思维题,代码如下:
#include <bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
int t;
int n;
cin>>t;
while(t--)
{
cin>>n;
for(int i=2;i<=n;i++)
{
cin>>a[i];
}
if(n%2==1)
{
cout<<"No"<<endl;
continue;
}
int t=0;
int s=0;
int flag=0;
for(int i=n;i>=2;i--)
{
if(a[i]==1)
{
t++;
}
else if(a[i]==2)
{
s++;
}
if(t<s)
{
flag=1;
break;
}
}
if(flag==1)
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
}
}
return 0;
}
G - H HDU - 6030
题意:
给你一个长度为n的序列,每个位置为红色或者蓝色,任意取素数个长度的子序列,均满足红色的个数不小于蓝色,问共有多少种情况?
思路:
规律题,找了好久才发现,一开始理解错题意,后来发现错误,其实1的时候应该是2,虽然n取不到1,然后就会发现规律:
F [ n ] = F [ n - 1 ] + F [ n - 3 ];
然后看了看范围,n的范围是10的18次方,数组肯定存不开,于是想到了矩阵快速幂。下面是代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<math.h>
#include<algorithm>
#include<stack>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
struct matrix
{
ll m[5][5];
};
matrix mutil(matrix a,matrix b)
{
matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
for(int k=1;k<=3;k++)
{
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
}
c.m[i][j]%=mod;
}
}
return c;
}
matrix powmod(matrix a,ll k)
{
matrix ans;
memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=3;i++)
ans.m[i][i]=1;
while(k)
{
if(k&1)
{
ans=mutil(ans,a);
k--;
}
k>>=1;
a=mutil(a,a);
}
return ans;
}
int main()
{
int t;
ll n,res;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
if(n==2)
printf("3\n");
else if(n==3)
printf("4\n");
else if(n==4)
printf("6\n");
else
{
matrix a,b,c,d;
a.m[1][1]=1;a.m[1][2]=0;a.m[1][3]=1;
a.m[2][1]=1;a.m[2][2]=0;a.m[2][3]=0;
a.m[3][1]=0;a.m[3][2]=1;a.m[3][3]=0;
memset(c.m,0,sizeof(c.m));
c.m[1][1]=6;c.m[2][1]=4;c.m[3][1]=3;
b=powmod(a,n-4);
d=mutil(b,c);
printf("%lld\n",d.m[1][1]);
}
}
}