codeforces round 315 div2 題解

數學專場..

A : 推公式

#include <bits/stdc++.h>
using namespace std;
int t,s,q;

int main(){
	cin>>t>>s>>q;
	int res = 0;
	while(s<t){
		int x = s*q;
		s = x;
		res++;
	}	
	cout<<res<<endl;
	return 0;
}

B: 考慮中間那個位置亂搞一下

#include <bits/stdc++.h>
using namespace std;
map<int, int> m;
map<int, int> m2;
int a[100010];
int ans[100010];
int main(){
	int n;
	cin>>n;
	for(int i=1; i<=n; i++){
		scanf("%d", &a[i]);
		m[a[i]]++;
	}
	int k=1;
	for(int i=1; i<=n; i++){
		if(m[a[i]] > 1||a[i] > n){
			m[a[i]] --;
			ans[i] = -1;
		}
		else ans[i] = a[i], m2[a[i]] = true;
	}
	for(int i=1; i<=n; i++){
		if(ans[i] == -1){
			while(k<=n&&m2[k])
				k++;
			ans[i] = k;
			m2[k] = true;
		}
	}
	for(int i=1; i<=n; i++)
		printf("%d ", ans[i]);
	return 0;
}


C: 大暴力。。。
 #include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<math.h>
using namespace std;
#define maxn 2000020
int flag[maxn],num[maxn];
int pal[maxn];
int gcd(int a,int b){
	if(b!=0) return gcd(b,a%b);
	else return a;
}
void getprime(){
	fill(num,num+1+maxn,1);
	num[0]=num[1]=0;
	int t=0;
	for(int i=2;i<=maxn;i++){
		if(num[i]){
			for(int j=2*i;j<=maxn;j+=i){
				num[j]=0;
			}
		}
		num[i]+=num[i-1];
	}
}
bool judge(int n){
	int t=0;
	while(n){
		pal[t++]=n%10;
		n=n/10;
	}
	for(int i=0;i<t/2;i++){
		if(pal[i]!=pal[t-1-i]) return false;
	}
	return true;
}
int main(){
	getprime();
	int m=0,c=0;
	int p,q;
	scanf("%d%d",&p,&q);
	int lmax=-1;
	for(int i=1;i<=maxn;i++){
		if(judge(i)&&i!=0) c++;
		if(q*num[i]<=p*c){
			lmax=i;
		}
	}
	if(lmax==-1) printf("Palindromic tree is better than splay tree\n");
	else printf("%d\n",lmax);
}

D: 首先給出集合中的三種關係: 自反, 對稱,傳遞, 兩個集合等價的定義是同時具有自反對稱和傳遞性。 這裏求的是滿足傳遞和對稱性,但不是等價集合的集合個數。

首先,如果對於一個二元組 <x, y> 如果它滿足傳遞和對稱性的話 那麼可以推出<x, y> == <y, x> -> <x, x> 也就是說x, y都滿足自反性。 這樣的話,我們就可以把這個集合的元素分成若干個塊,每一個塊內都是一個滿足自反,傳遞, 對稱的這麼一個塊, 那麼我們只需要不讓所有的元素都放在集合裏面就可以了。

ok。。。 那麼首先我們熟悉一下第二類斯特林數。 string[I][j] = string[I-1][j]*j + string[I-1][j-1];  這個是遞推公式。 string[I][j]代表I個元素分成j個集合的劃分方案。

那麼對於每一個i來說的話, f[I] 就是I個元素所能分配的個數,且集合不爲空。 f[I] = sum(string[I][k]) 1<=k<=I;

那麼對於這道題答案就不是就是C(n,i)*f[I]+1  1<=I<=n-1;

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<list>
#include<map>
#include<set>
#include<queue>
#include<deque>
#include<vector>
#include<functional>
#include<string>

#define INF 1000000007
#define pb push_back
#define mp make_pair
#define ll long long
#define rep(i,k) for(int i=G.start[k];i!=INF;i=G.next[i])

using namespace std;

int n;
long long st[4005][4005],f[4005];
int C[4005][4005];

void Stirling()
{
	for(int i=0;i<4005;i++)
		st[i][0]=st[i][1]=1;
	for(int i=2;i<4005;i++)
		for(int j=2;j<=i;j++)
			st[i][j]=(st[i-1][j-1]+j*st[i-1][j])%INF;
	for(int i=0;i<4005;i++)
		for(int j=1;j<=i;j++)
			f[i]=(f[i]+st[i][j])%INF;
}

void C0()
{
	for(int i=0;i<4005;i++)
		C[i][0]=C[i][i]=1;
	for(int i=1;i<4005;i++)
		for(int j=1;j<=i;j++)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%INF;
}

int main()
{
	ios::sync_with_stdio(false);
	
	cin>>n;
	Stirling();
	f[0]=1;
	C0();
	long long ans=0;
	for(int i=1;i<=n-1;i++){
		ans=(ans+(C[n][i]*(ll)f[i])%INF)%INF;
	}
	ans++;
	cout<<ans<<endl;
	return 0;
}

E: 2-sat判定  好題!!

看了一天還是不會做的2-sat。。。 這裏膜拜一下sjut的toosimple牛。。 順便膜拜一下代碼:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=(a);i<=(n);i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
#define Fast_IO ios_base::sync_with_stdio(0);cin.tie(0)

namespace SAT2 {
	const int N = 410;
	VI e[N];
	int top,Index,scc,Instack[N],Stack[N],DFN[N],Low[N];
	int Belong[N];
	void init(){
		rep(i, 0, N-1) e[i].clear();
	}	
	void add_edge(int u, int v){
		e[u].pb(v);
	}
	void tarjan(int u){
		DFN[u] = Low[u] = ++Index;
		Instack[u] = true;
		Stack[top++] = u;
		int size = e[u].size();
		for(int i=0; i<size; i++) {
			int v = e[u][i];
			if(!DFN[v]){
				tarjan(v);
				Low[u] = min(Low[u], Low[v]);
			}
			else if(Instack[v]&&Low[u] > DFN[v])
				Low[u] = DFN[v];
		}
		if(Low[u] == DFN[u]){
			scc++;
			while(true){
				int tmp = Stack[--top];
				Instack[tmp] = false;
				Belong[tmp] = scc;
				if(tmp == u) break;	
			}
		}
	}
	void solve(int n){
		scc = Index = top = 0;
		memset(DFN, 0, sizeof(DFN));	
		for(int i=0; i<2*n; i++)
			if(!DFN[i]) tarjan(i);
	}
}
int l;
int n,m;
char str[400];
char s[100100];
PII e[201000];
char ret[500];
int wc, wv;
bool check(int d){
	SAT2::init();
	for(int i =0; i<m; i++){
		SAT2::add_edge(e[i].first, e[i].second);
		SAT2::add_edge(e[i].second^1, e[i].first^1);
	}
	for(int i=0; i<=d; i++){
		if(str[ret[i] - 'a'] == 'V') SAT2::add_edge(2*i+1, 2*i);
		else SAT2::add_edge(2*i, 2*i+1);
	}		
	for(int i=0; i<n; i++){	
		if(wc) SAT2::add_edge(2*i, 2*i+1);
		if(wv) SAT2::add_edge(2*i+1, 2*i);
	}
	SAT2::solve(n);
	for(int i=0; i<n; i++)
		if(SAT2::Belong[2*i] == SAT2::Belong[2*i+1])
			return false;
	return true;
}

void dfs(int d, int f){
	if(d == n) {
		puts(ret);
		throw 0;
	}
	int v = 0, c= 0;
	rep(i, (f?0:s[d]-'a'), l-1){
		ret[d] = i+'a';
		if(str[i] == 'V'){
			if(v >= 2) continue;
			v++;
		}
		else {
			if(c >= 2) continue;
			c++;
		}
		if(check(d)){
			dfs(d+1, f|(i!=s[d]-'a'));	
		}
	}
}

int main()
{ 
	wc = 1;
	wv = 1;
	scanf("%s", str);
	l = strlen(str);
	rep(i, 0, l-1) wc &= (str[i] == 'C'), wv&=(str[i] =='V');
	cin>>n>>m;
	rep(i, 0, m-1){
		int t1,t2;
		char c1[3], c2[3];
		scanf("%d %s %d %s", &t1, c1, &t2, c2);	
		t1--; t2--;
		t1 = c1[0] == 'V'?2*t1:2*t1+1;
		t2 = c2[0] == 'V'?2*t2:2*t2+1;
		e[i] = mp(t1, t2);
	}	
	scanf("%s", s);
	try{
		dfs(0, 0);
	}	
	catch(int e){
		return 0;
	}
	puts("-1");
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章