Codeforces Round #338 (Div. 2)

題目鏈接:http://codeforces.com/contest/615

第一題:

很簡單

#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;
}




















發佈了61 篇原創文章 · 獲贊 53 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章