刷题

CF1516B AGAGA XOOORRR

题目大意:每次操作可以将相邻两个数异或起来变成一个数,问能否存在一种方案,将数列进行操作后所有剩下的数相等(至少剩下两项)。

每次只能操作相邻两项,最终剩下的数一定是原数列中的连续一段。考虑第一个数和后面哪些数一起,即可枚举出答案,每次找到能满足答案的分配的最远的即可。

最远是为了解决3 3 0这种情况, 0不能被很好的考虑进去

复杂度n ^ 2

#include<bits/stdc++.h>
#define ll long long
#define db double

using namespace std;

int readint() {
	int rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

ll readll() {
	ll rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}
const int maxn = 2005;
int T, n, a[maxn], sum[maxn];
bool flag = 0;

void input() {
	n = readint();
	for (int i = 1; i <= n; i++) a[i] = readint(), sum[i] = sum[i - 1] ^ a[i];
	flag = 0;
}

bool check(int s) {
	int tmp = sum[s];
	int lf = s;
	while (1) {
		bool f = 0;
		for (int i = n; i >= lf + 1; i--) {
			if ((sum[i] ^ sum[lf]) == tmp) {
				lf = i;
				f = 1;
				break;
			}
		}
		if (!f || lf == n) break;
	}
	return lf == n;
}

void solve() {
	for (int i = 1; i <= n - 1; i++) {
		if (check(i)) {
			flag = 1;
			break;
		}
	}
}

void output() {
	if (flag) {
		puts("YES");
	} else {
		puts("NO");
	}
}

int main() {
	T = readint();
	while (T--) {
		input();
		solve();
		output();
	}
	return 0;
}

CF1514C. Product 1 Modulo N

题目大意:有1 ~ (n - 1)的数,取出一个最长的子序列,让他们的乘积mod(n)为1

首先考虑最终答案中的数有什么特点, 比如有一个数x, 其他数的乘积为sum, x * sum % n = 1, sum为x在n下的逆元,有逆元的条件是gcd(x,n) = 1, 将这些数加进新数组中并求sum

考虑这个sum中怎么删去一个数让他变成合法答案, 考虑删除中间的一个数x后成立, x * 1 % n = sum, 即删除sum这个数后成立,特殊考虑一下sum = 1的情况

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 5;
int n;
int a[maxn], sum, cnt;
int pos;

int gcd(int x, int y) {
	if (!y) return x;
	return gcd(y, x % y);
}

int main() {
	scanf("%d", &n);
	sum = 1;
	for (int i = 1; i < n; i++) {
		if (gcd(i, n) == 1) {
			a[++cnt] = i;
			sum = 1LL * sum * i % n;
		}
	}
	if (sum == 1) {
		printf("%d\n", cnt);
		for (int i = 1; i <= cnt; i++) printf("%d ", a[i]);
	} else {
		for (int i = 1; i <= cnt; i++) {
			if (a[i] % n == sum) {
				pos = i;
				break;
			}
		}
		printf("%d\n", cnt - 1);
		for (int i = 1; i <= cnt; i++) {
			if (pos != i) printf("%d ", a[i]);
		}
	}
	return 0;
}

CF1513C. Add One

题目大意:将一个数拆成单个的数字,每次将每个数字加1得到一个新的数,求操作m次之后的该数的长度

考虑到只有9在操作一次之后变成了10,可以拆分成1和0的贡献,考虑递推

dp[i][j]表示i这个数字操作了j次之后的长度

0 - 8正常转移,9的时候拆成1和0的贡献相加

#include<bits/stdc++.h>
#define ll long long
#define db double

using namespace std;

int readint() {
	int rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

ll readll() {
	ll rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

const int maxn = 2e5 + 5;
const int Mod = 1e9 + 7;
int T, n, m;
int f[10][maxn]; 
int ans = 0;
void input() {
	n = readint(), m = readint();
	ans = 0;
}

void solve() {
	while (n) {
		ans += f[n % 10][m];
		ans %= Mod;
		n /= 10;
	}
}

void output() {
	printf("%d\n", ans);
}

int main() {
	T = readint();
	for (int i = 0; i <= 9; i++) f[i][0] = 1;
	for (int i = 1; i <= 2e5; i++) {
		for (int j = 0; j <= 8; j++) f[j][i] = f[j + 1][i - 1];
		f[9][i] = (f[1][i - 1] + f[0][i - 1]) % Mod;
	}
	while (T--) {
		input();
		solve();
		output();
	}

	return 0;
}

CF1512F. Education

题目大意:每天你可以有两种操作:

1.在第i层挣a[i]

2.在钱足够b[i]的情况下升到i+1层,钱减少b[i]

问钱达到c的时候最少需要多少天

最终的答案可以分解为到达第i层的天数和在第i层的天数

对于每一层,需要挣到给定钱数的天数可以O(1)的求出。

对于上到i层的天数可以递推出 有一个小贪心,能上就上一定是最优的

然后枚举最后到了第几层即可 注意考虑一天挣很多钱的情况

#include<bits/stdc++.h>
#define ll long long
#define db double

using namespace std;

int readint() {
	int rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

ll readll() {
	ll rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		rt = (rt << 1) + (rt << 3) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}
const int maxn = 2e5 + 5;
int T, n;
ll ans;
ll c, a[maxn], b[maxn], d[maxn], r[maxn];

void input() {
	ans = 1e9;
	n = readint();
	c = readll();
	for (int i = 1; i <= n; i++) a[i] = readll();
	for (int i = 1; i <= n - 1; i++) b[i] = readll();
}

void solve() {
	r[1] = 0;
	d[1] = 0;
	for (int i = 2; i <= n; i++) {
		if (r[i - 1] >= b[i - 1]) {
			d[i] = d[i - 1] + 1;
			r[i] = r[i - 1] - b[i - 1];
		} else {
			ll t = (b[i - 1] - r[i - 1] + a[i - 1] - 1) / a[i - 1];
			d[i] = d[i - 1] + t + 1;
			r[i] = r[i - 1] + a[i - 1] * t - b[i - 1];
		}
	}
	for (int i = 1; i <= n; i++) {
		if (c <= r[i]) ans = min(ans, d[i]);
		else ans = min(ans, d[i] + (c - r[i] + a[i] - 1) / a[i]);
	}
}

void output() {
	printf("%d\n", ans);
}

int main() {
	T = readint();
	while (T--) {
		input();
		solve();
		output();
	}
	return 0;
}

CF1512G. Short Task

题目大意:定义函数d(n)为n的因子和,求d(n) = C的最小的n值, 没有输出-1

显然线性筛,考虑线性筛怎么求因数和:

  • 对于p∈primesp∈primes,显然有d[p]=p+1d[p]=p+1.

  • 对于ii,若i%primes[j]==0i%primes[j]==0说明primes[j]primes[j]不是ii的最小因子,把因数和公式展开后可以得到结论:d[i∗primes[j]]=d[i]∗(primes[j]+1)d[i∗primes[j]]=d[i]∗(primes[j]+1)

  • 若i%pirmes[j]!=0i%pirmes[j]!=0说明primes[j]primes[j]是ii的最小因子,考虑维护每个数对应的最小质因子的在约数和中的贡献:即1+p+p2+...pw11+p+p2+...pw1,其中pp是ii的最小质因子。则d[i∗primes[j]]=d[i]/minp[i]∗minp[i∗primes[j]]d[i∗primes[j]]=d[i]/minp[i]∗minp[i∗primes[j]].

  • 维护minpminp部分:质数显然,若primes[j]primes[j]不是ii的最小质因子,那么minp[i∗primes[j]]=primes[j]+1minp[i∗primes[j]]=primes[j]+1.否则minp[i∗primes[j]]=minp[i]∗primes[j]+1minp[i∗primes[j]]=minp[i]∗primes[j]+1.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    typedef pair<int,int> pii;
    #define x first
    #define y second
    
    const int N = 1e7+7;
    int primes[N],cnt,ans[N];
    ll minp[N],dsum[N];
    bool st[N];
    
    void init()
    {
    	dsum[1] = 1;
    	for(int i = 2;i < N;++i)
    	{
    		if(!st[i])	primes[cnt++] = i,dsum[i] = i + 1,minp[i] = i + 1;
    		for(int j = 0;j < cnt && 1ll*primes[j] * i < N;++j)
    		{
    			st[primes[j] * i] = 1;
    			if(i % primes[j])	dsum[i * primes[j]] = dsum[i] * (primes[j] + 1),minp[i * primes[j]] = primes[j] + 1;
    			else
    			{
    				minp[i * primes[j]] = minp[i] * primes[j] + 1;
    				assert(minp[i] != 0);
    				dsum[i * primes[j]] = dsum[i] / minp[i] * minp[i * primes[j]];
    				break;
    			}
    		}
    	}
    	forn(i,1,N - 1)	if(dsum[i] < N && !ans[dsum[i]])	ans[dsum[i]] = i;
    }
    
    int main()
    {
    	init();
    	
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		int n;scanf("%d",&n);
    		printf("%d\n",ans[n] == 0 ? -1 : ans[n]);
    	}
        return 0;
    }

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值