codeforces AIM Tech Round

感觉半夜撸代码就像傻逼。。


Graph and String

用a和c二分染色,


#include <bits/stdc++.h>

using namespace std;


#define N 1000
#define M 2000000
#define ULL unsigned long long 
#define LL long long
#define mod 1000000007


int fst[N], vv[M], nxt[M], e;
void init() {
e = 0;
memset(fst, -1, sizeof fst);
}


void add(int u,int v){ 
vv[e] = v, nxt[e] = fst[u], fst[u] = e ++;
}
int g[N][N];
bool vis[N];
bool flag;
char s[N];


void dfs(int u, int p) {
vis[u] = 1;
s[u] = p+'a';
p = 2-p;
for(int i = fst[u]; ~i; i = nxt[i]) {
int v = vv[i];
if(vis[v]) {
if(s[v] != p+'a')
flag = 1;
continue;
}
dfs(v, p);
}
}




int main() {
int n, m;
scanf("%d%d", &n, &m);
init();
int u, v;
for(int i = 0; i < m; ++i) 
scanf("%d%d", &u, &v), g[u][v] = g[v][u] = 1;
for(int i = 1; i <= n; ++i) 
for(int j = i+1; j <= n; ++j) 
if(g[i][j] == 0)
add(i, j), add(j, i);
for(int i = 1; i <= n; ++i) if(!vis[i]){
if(fst[i] == -1) s[i] = 'b';
else dfs(i, 0);
}
if(flag) {
puts("No");
return 0;
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) 
{
if(i == j) continue;
if(g[i][j] == 1 && abs(s[i]-s[j]) > 1)
{

puts("No");
return 0;
}
if(g[i][j] == 0 && abs(s[i] - s[j]) <= 1)
{
puts("No");
return 0;
}
}
}
s[n+1] = 0;
printf("Yes\n%s\n", s+1);

}


Array GCD

题意:

操作一 最多删掉一个区间,花费len×a 

操作二 a[i] +- 1, 花费b

把序列gcd改为不为1的最小花费


由于a[1] 或a[n] 不能删

枚举他们+-1的质因子,它的倍数作为最后的gcd 的

dp[i][0]表示还没有开始删区间

dp[i][1]表示正在删区间

dp[i][2]表示已经删完了一个区间


#include <bits/stdc++.h>
using namespace std;

#define N (1000000 + 10)
#define M 2000000
#define inf (long long)1e17
#define ULL unsigned long long 
#define LL long long
#define mod 1000000007

int a,b, c[N];
int cnt, d[N];
	int n;

void gao(int x) {
	for(int i = 2; i * i <= x; ++i) {
		if(x % i == 0) {
			d[cnt++] = i;
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) d[cnt++] = x;
}


LL dp[N][3];

LL f(int p) {
	dp[0][0] = 0;
	dp[0][1] = dp[0][2] = inf;

	for(int i = 1; i <= n; ++i) {
		for(int j = 0; j < 3; ++j)
			dp[i][j] = inf;
		if(c[i] % p == 0) {
			dp[i][0] = dp[i-1][0];
			dp[i][1] = min(dp[i-1][0] + a, dp[i-1][1] + a);
			dp[i][2] = min(dp[i-1][2], dp[i-1][1]);
		}
		else if((c[i]+1)%p == 0 || (c[i]-1+p)%p == 0) {
			dp[i][0] = dp[i-1][0] + b;
			dp[i][1] = min(dp[i-1][0] + a, dp[i-1][1] + a);
			dp[i][2] = min(dp[i-1][2] + b, dp[i-1][1] + b);
		}
		else {
			dp[i][1] = min(dp[i-1][0] + a, dp[i-1][1] + a);
		}
	}
	return min(min(dp[n][0], dp[n][1]), dp[n][2]);
}



int main() {
	scanf("%d%d%d", &n, &a, &b);
	for(int i = 1; i <= n; ++i)
		scanf("%d", &c[i]);
	for(int i = -1; i <= 1; ++i) {
		gao(c[1]+i); gao(c[n] + i);
	}

	sort(d, d + cnt);
	cnt = unique(d, d+cnt) - d;
	LL ans = inf;
	for(int i = 0; i < cnt; ++i)
		ans = min(ans, f(d[i]));
	printf("%I64d\n", ans);

}
Birthday
奇葩概率题,好像暴力算期望
Transforming Sequence
题意:
用1到2^k-1的数组成a[1] 到a[n]
使得b[i]严格递增的方案数有多少,b[i] = a[1] | a[2]……| a[i]
dp[n][k]表示前n个数二进制位上共k个1
转移是n^3
用倍增省掉第一维然后用fft加速 做到nlognlogn
涨姿势啊
#include <bits/stdc++.h>
using namespace std;

#define pii pair<int, int>
#define MP make_pair
#define ls (i<<1)
#define rs (i<<1|1)
#define md (ll+rr>>1)
#define N (1000000 + 10)
#define M (2000000 + 10)
#define inf 0x3f3f3f3f
#define ULL unsigned long long 
#define LL long long
#define mod 1000000007


// 多项式乘法 系数对MOD=1000000007取模, 常数巨大,慎用
// 只要选的K个素数乘积大于MOD*MOD*N,理论上MOD可以任取。
#define MOD 1000000007
#define K 3

const int m[K] = {1004535809, 998244353, 104857601};
#define G 3


int qpow(int x, int k, int P) {
	int ret = 1;
	while(k) {
		if(k & 1) ret = 1LL * ret * x % P;
		k >>= 1;
		x = 1LL * x * x % P;
	}
	return ret;
}

struct _NTT {
	int wn[25], P;

	void init(int _P) {
		P = _P;
		for(int i = 1; i <= 21; ++i) {      
			int t = 1 << i;      
			wn[i] = qpow(G, (P - 1) / t, P);      
		}
    }
	void change(int *y, int len) {
		for(int i = 1, j = len / 2; i < len - 1; ++i) {      
			if(i < j) swap(y[i], y[j]);      
			int k = len / 2;      
			while(j >= k) {      
				j -= k;      
				k /= 2;      
			}      
			j += k;      
		} 
	}
	void NTT(int *y, int len, int on) {
		change(y, len);      
		int id = 0;      
      
		for(int h = 2; h <= len; h <<= 1) {      
			++id;      
			for(int j = 0; j < len; j += h) {      
				int w = 1;      
				for(int k = j; k < j + h / 2; ++k) {      
					int u = y[k];      
					int t = 1LL * y[k+h/2] * w % P;     
					y[k] = u + t;      
					if(y[k] >= P) y[k] -= P;      
					y[k+h/2] = u - t + P;      
					if(y[k+h/2] >= P) y[k+h/2] -= P;  
					w = 1LL * w * wn[id] % P;
				}      
			}      
		}      
		if(on == -1) {      
			for(int i = 1; i < len / 2; ++i) swap(y[i], y[len-i]);      
			int inv = qpow(len, P - 2, P);      
			for(int i = 0; i < len; ++i)   
				y[i] = 1LL * y[i] * inv % P;
		}      
	}
	void mul(int A[], int B[], int len) {
		NTT(A, len, 1);
		NTT(B, len, 1);
		for(int i = 0; i < len; ++i) A[i] = 1LL * A[i] * B[i] % P;
		NTT(A, len, -1);
	}
}ntt[K];

int tmp[N][K], t1[N], t2[N];
int r[K][K];

int CRT(int a[]) {
	int x[K];
	for(int i = 0; i < K; ++i) {
		x[i] = a[i];
		for(int j = 0; j < i; ++j) {
			int t = (x[i] - x[j]) % m[i];
			if(t < 0) t += m[i];
			x[i] = 1LL * t * r[j][i] % m[i];
		}
	}
	int mul = 1, ret = x[0] % MOD;
	for(int i = 1; i < K; ++i) {
		mul = 1LL * mul * m[i-1] % MOD;
		ret += 1LL * x[i] * mul % MOD;
		if(ret >= MOD) ret -= MOD;
	}
	return ret;
}

void mul(int A[], int B[], int len) {
	for(int id = 0; id < K; ++id) {

		for(int i = 0; i < len; ++i) {
			t1[i] = A[i];
			t2[i] = B[i];
		}
		ntt[id].mul(t1, t2, len);
		for(int i = 0; i < len; ++i) 
			tmp[i][id] = t1[i];
	}
	for(int i = 0; i < len; ++i) {
		A[i] = CRT(tmp[i]);

	}
}

void init() {
	for(int i = 0; i < K; ++i) {
		for(int j = 0; j < i; ++j) {
			r[j][i] = qpow(m[j], m[i] - 2, m[i]);
		}
	}
	for(int i = 0; i < K; ++i) {
		ntt[i].init(m[i]);
	}
}
int ff[N], nff[N];
int dp[N];
int ans[N];
int pow2[N];
int ta[N], tb[N];

void mymul(int *A, int *B, int k, int lb) {
	int tlen = 1;
	while(tlen < (k+1) * 2) tlen <<= 1;
	for(int i = 0; i <= tlen; ++i)
		ta[i] = tb[i] = 0;
	for(int i = 0; i <= k; ++i)
		ta[i] = 1LL * A[i] * nff[i] % mod * qpow(2, i*lb, mod) % mod;
	for(int i = 0; i <= k; ++i)
		tb[i] = 1LL * B[i] * nff[i] % mod;
	//debug
//	for(int i = 0; i <= k; ++i)
//		printf("aa %d bb %d\n", ta[i], tb[i]);
//
	mul(ta, tb, tlen);
	//debug
//	for(int i = 0; i <= k; ++i)
//		printf("ta %d\n", ta[i]);
	for(int i = 0; i <= k; ++i)
		A[i] = 1LL * ta[i] * ff[i] % mod;
}


int main() {
	LL nn;
	int n, k;
	scanf("%I64d%d", &nn, &k);
	if(nn > k) {
		puts("0");
		return 0;
	}
	n = nn;
	ff[0] = nff[0] = 1;
	for(int i = 1; i <= k*30; ++i)
		ff[i] = 1LL * ff[i-1] * i % mod, nff[i] = qpow(ff[i], mod-2, mod);
	pow2[0] = 1;
	for(int i = 1; i <= k*30; ++i)
		pow2[i] = 1LL * pow2[i-1] * 2 %mod;

	for(int i = 1; i <= k; ++i) 
		dp[i] = 1;

	init();
	int len = 1;
	ans[0] = 1;
	for(int z = n; z; z >>= 1) {
		
		if(z & 1) {
			mymul(ans, dp, k, len);
//			for(int i = 0; i <= k; ++i)
//				printf("&1 r %d\n", ans[i]);
		}
		mymul(dp, dp, k, len);
	//	for(int i = 0; i <= k; ++i)
	//		printf("dp %d\n", dp[i]);
		len += len;
	}
	int res = 0;
	for(int i = 0; i <= k; ++i)
		res = (res + 1LL * ans[i] * ff[k] % mod * nff[i] % mod * nff[k-i] % mod) %mod;
	printf("%d\n", res);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值