第一题:
很简单
#include<bits/stdc++.h>
using namespace std;
int nn[140];
int main(){
int n,m;
while(cin>>n>>m){
memset(nn,0,sizeof(nn));
for(int i = 0;i<n;i++){
int a;
cin>>a;
for(int j = 0;j<a;j++){
int b;
cin>>b;
b--;
nn[b] = 1;
}
}int ans = 0;
for(int i = 0;i<m;i++){
if(nn[i] == 1)ans++;
}
if(ans==m)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
第二题:对于我这种英语渣渣,题意太难理解了。但也不难。
题意:
在一张纸上有一个n个点,m条边的无向图,并且没有指向自己的边。找出一个严格递增的相连的线路,记录这条线路的点数a,并记录这条线路末尾最大的点有几天相邻的边b,求a×b的最大值。
解题思路:
利用动态规划的思想,dp[i] = max(dp[i],dp[j]+1)其中j<i,并且(i,j)相连,这样就求出结尾为i的tail的最大长度。然后它的spines就是与i相连的点的个数。求出两者相乘的最大的值。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100050;
typedef long long ll;
vector<int>V[maxn];
int dp[maxn];
int main(){
int n,m;
cin>>n>>m;
for(int i = 0;i<m;i++){
int a,b;
cin>>a>>b;
V[a].push_back(b);
V[b].push_back(a);
}
memset(dp,0,sizeof(dp));
dp[1] = 1;ll ans = 1;
for(int i = 1;i<=n;i++){
dp[i] = 1;
for(int j = 0;j<V[i].size();j++){
if(i>V[i][j]){
dp[i] = max(dp[i],dp[V[i][j]]+1);
}
}
int t = V[i].size();
//cout<<t<<" "<<dp[i]<<endl;
ans = max(ans,1ll*dp[i]*t);
}
cout<<ans<<endl;
}
第三题:这道题进了思想误区,导致比赛结束后wa掉了。
题意:给两个字串a,b。在a或reverse(a)中截取k个字串,让这些字串拼接成b串,求k的最小值,并输出截取字串的起始x和终止位置y。在a中的x<y,在reverse(a)中x>y。如果不能拼接成b,输出-1。
解题思路:
不能拼接成时,为b中包含a中不含有的字母。
能拼接成时
ans = 0 for i in b: ma = 0 for j in a: cnt = 0;ii = i;jj = j(1) while ii == jj: (2) ii++;jj++;cnt++ (3) ma = max(ma,cnt) for j in reverse(a): (1)(2)(3) i+=ma-1;ans++ print ans
ma是一次字串的最大长度,cnt是每次对比的最大长度,ans是字串段数,然后记 录一下jj-ma+1和jj
#include<bits/stdc++.h>
using namespace std;
int aa[27];
int bb[27];
int qi[2500];
int ho[2500];
int main(){
string a,ar,b;
cin>>a;
cin>>b;
ar = a;
reverse(ar.begin(),ar.end());
int al = a.size();
int bl = b.size();
for(int i = 0;i<al;i++)aa[a[i]-'a'] = 1;
for(int i = 0;i<bl;i++)bb[b[i]-'a'] = 1;
for(int i = 0;i<26;i++){
if(aa[i]==0&&bb[i]==1){cout<<"-1"<<endl;return 0;}
}
int ans = 0;
for(int i = 0;i<bl;i++){
int ma = 0,ma1= 0;
for(int j = 0;j<al;j++){
int ii = i;int cnt = 0;int yn = 0;int jj = j;
while(b[ii] == a[jj]){ii++;jj++;cnt++;if(ii>=bl)break;if(jj>= al)break;yn = 1;}
ma1 = max(ma,cnt);
if(ma1 !=ma){qi[ans] = jj-ma1+1;ho[ans] = jj;}
ma = ma1;
}
for(int j = 0;j<al;j++){
int ii = i;int cnt = 0;int yn = 0;int jj = j;
while(b[ii] == ar[jj]){ii++;jj++;cnt++;if(ii>=bl)break;if(jj>= al)break;yn = 1;}
ma1 = max(ma,cnt);
if(ma1 !=ma){qi[ans] = jj;ho[ans] = jj-ma1+1;}
ma = ma1;
}
i+=ma-1;
ans++;
}
cout<<ans<<endl;
for(int i = 0;i<ans;i++){
cout<<qi[i]<<" "<<ho[i]<<endl;
}
return 0;
}
第四题:水平太洼,比赛的时候不会做。
题意:给n各质数,求这n各质数相乘的值m的所有的因子的乘积mod(1e9+7)。例如给出3个质数2,2,3。乘积为12。让求1×2×3×4×6×12mod(1e9+7)的值。
解题思路:
小于200000的素数不是很多,所以肯定有很多重复的数字。开一个map,记录素数和对应的个数。
然后看组合情况,假设素数j有k个,那么j有(kj+1)种出现的形式,所以对于所有的素数就有(k1+1)×(k2+1)×(k3+1)×(k4+1)*...*(kn+1)= sum种组合方式。不考虑j时就有sum/(kj+1)种。假设其中一种除j外的乘积为a,那么就有(a)×(a×j)×(a× j^2)×(a×j^3)×...×(a×j^kj) = (a^(kj+1))×(j^(kj*(kj+1)/2)) .所以在所有的情况中共乘了j^((kj*(kj+1)/2))^(sum/(kj+1)).对于每一个素数求解一遍,乘积mod(1e9+7)为结果。
但是因为数据量过大,会导致sum爆 long long,所以在求解每一个j的sum/(kj+1)时要想办法。
我们用cnt(j)表示j^((kj*(kj+1)/2))
所以我们用d表示遍历到j时的种类的个数,即d(j)= (k1+1)×(k2+1)×(k3+1)×...×(kj+1)
然后
d(0)=1;ans = 1; for j in ma: cnt(j) ans=ans^(k+1)*cnt(j)^d(j-1); d(j) ans为最终结果 例如我们有一组数据2 2 3 5 5 则
cnt(1) = 2^(2*3/2)=8,cnt(2)=3^(1+2/2)cnt(3) j = 1: ans = cnt(1)^1 d(1)=d(0)*(k1+1)=(k1+1) j = 2: ans = cnt(1)^1^(k2+1)*cnt(2)^(k1+1) d(2) =d(1)*(k2+1)= (k1+1)*(k2+1) j = 3: ans = cnt(1)^1^(k2+1)^(k3+1)*cnt(2)^(k1+1)(k3+1)*cnt(3)^(k1+1)*(k2+1) d(3) = d(2)*(k3+1)
并且在本解法中没有sum/k的运算。由费马小定理若p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p),则a^x≡a^(x%(m-1))(mod p)
所以再加上%mod得到:
d(0)=1;ans = 1; for j in ma: cnt(j) ans=ans^(k+1)%mod*cnt(j)^d(j-1)%mod; d(j)%(mod-1) 然后再用快速幂解法
ll fast_mod(ll n,ll m,ll mod){
ll ans =1;
while(m){
if(m&1)ans = ans*n%mod;
m>>=1;
n = n*n%mod;
}
return ans;
}
即可快速的求解出ans。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p[200050];
map<int ,ll>MA;
const ll mod = 1e9+7;
ll fast_mod(ll n,ll m,ll mod){
ll ans =1;
while(m){
if(m&1)ans = ans*n%mod;
m>>=1;
n = n*n%mod;
}
return ans;
}
int main(){
int T;
cin>>T;
MA.clear();
for(int i = 0;i<T;i++){
int a;
scanf("%d",&a);
MA[a]++;
}
map<int,ll>::iterator it;
ll sum = 1;
ll ans = 1;
for(it = MA.begin();it!=MA.end();it++){
int cnt = fast_mod(it->first,(it->second+1)*it->second/2,mod);
ans=fast_mod(ans,it->second+1,mod)*fast_mod(cnt,sum,mod)%mod;
sum=sum*(it->second+1)%(mod-1);
}
printf("%I64d\n",ans);
}
第五题:找公式??
题解:
我们根据例子发现,每往外一层增加6步,所以我们可以求出给出步数k的层数nn。
然后我们发现每一层有六条边,每一条边的步数为层数nn。
我们可以求出要求步数k的层数nn,边数bian,还有在该边的第几步ge。
然后根据座标求解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n;
cin>>n;
if(n == 0){cout<<"0 0"<<endl;return 0;}
//int x,int y;
//cout<<"n"<<n<<endl;
ll nn =(n+5)/6;
ll ns = sqrt(nn*2);
while(ns*(ns+1)/2<nn)ns++;
ns--;
//cout<<ns<<endl;//完整的层数
ll cnt,bian,ge;
cnt = n-ns*(ns+1)/2*6-1;
bian = cnt/(ns+1);
ge = cnt%(ns+1);
ll cx,cy;
ll x,y;
ge++;ns++;
if(bian == 0){
cx = 2*ns;cy = 0;
x = cx-ge;
y = cy+ge*2;
}
if(bian == 1){
cx = ns,cy =2*ns;
x = cx-ge*2;
y = cy;
}
if(bian == 2){
cx = -ns,cy =2*ns;
x = cx-ge;
y = cy-ge*2;
}
if(bian == 3){
cx = -ns*2,cy =0;
x = cx+ge;
y = cy-ge*2;
}
if(bian == 4){
cx = -ns,cy =-2*ns;
x = cx+ge*2;
y = cy;
}
if(bian == 5){
cx = ns,cy =-2*ns;
x = cx+ge;
y = cy+ge*2;
}
cout<<x<<" "<<y<<endl;
}