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]); } } }