200天1000题(DAY 1)

200天1000题(DAY 1)

目前总题数: 0

目前CF分数: 1325

T1: (ABC 268)C - Chinese Restaurant

// 题解
const int N = 1e6 + 10;
/*
	模拟即可
	但是纯暴力是N^2的 会TLE
	考虑到要把 A[I] 移动到 p=I-1
	需要操作 a[i] - p % N 或者 (a[i]-p+1)%N
	或者 (a[i]-p-1)%N;
	用一个东西储存一下 x次操作的贡献
	输出最大贡献即可
	
	很神奇的一题((
*/

inline void sensei()
{
    int n;
    cin >> n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    vector<int> cnt(n+1);
    
    for(int i=1;i<=n;i++){
        int pos = i-1;
        cnt[(((a[i]-pos)%n)+n)%n]++;
        cnt[(((a[i]-pos-1)%n)+n)%n]++;
        cnt[(((a[i]-pos+1)%n)+n)%n]++;
    }
    int ans = -inf_ll;
    for(int i=0;i<=n;i++){
        ans = max(ans,cnt[i]);
    }
    cout << ans << endl;
}

signed main()
{
    sensei();    
    return 0;
}

T2 (ABC 267)C - Index × A(Continuous ver.)

/*
    题目的意思大概就是
    给定一个长度为n的序列a
    以及一个数字m
    要你找到一个长度为m的子序列b
    并且 sigma(bi*i) 最大
*/

/*
题解:
如果暴力写这题,必定会超时
因为时间复杂度为 O(N^2)

但是我们可以通过观察发现一个式子:
例如样例:

10 4
-3 1 -4 1 -5 9 -2 6 -5 3

我们只看前两组m

分别是 
alls = (-3)*1 + (1)*2 + (-4)*3 + (1)*4
alls =          (1)*1 + (-4)*2 + (1)*3 + (-5)*4

这么一看是不是有点做差求和内味了

于是我们得到了一个alls转移的式子:

alls = a[r]*m + (alls - pre[r-1] - pre[l-2]);
其中 r是当前枚举的子序列的右端点,l是左端点

通过这个式子我们可以写出这题
详细见代码

*/


inline void sensei()
{
    int n,m;
    cin >> n >> m;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    vector<int> pre(n+1);
    for(int i=1;i<=n;i++){
        pre[i] = pre[i-1] + a[i];
    }
    int l,r;
    r = m+1;
    l = 2;
    int alls = 0;
    int ans = -inf_ll;
    for(int i=1;i<=m;i++){
        alls += i*a[i];
    }
    ans = alls;
    while(r <= n){
        alls = a[r]*m+(alls-(pre[r-1]-pre[l-2]));
        ans = max(ans,alls);
        l++;
        r++;
    }
    cout << ans << endl;
}

signed main()
{
    sensei();
    return 0;
}

T3 (ABC 265)D - Iroha and Haiku (New ABC Edition)

/*
	题目大概意思:
		公式有点难打,建议看原题链接
*/

/*
	题解:
	根据原公式推出下面的式子
        s[y-1]  = P + s[x-1];
        s[z-1]  = Q + P + s[x-1];
        s[w-1]  = R + Q + P + s[x-1];
	放到一个set中然后枚举x即可
*/

const int N = 1e6 + 10;

inline void sensei()
{
	int n, p, q, r;
	cin >> n >> p >> q >> r;
	set<int> st;
	vector<int> a(n + 1);
	vector<int> pre(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		pre[i] = pre[i - 1] + a[i];
		st.insert(pre[i]);
	}
	for (int x = 1; x <= n; x++) {
        if(st.find(p+pre[x-1])!=st.end() and st.find(q+p+pre[x-1])!=st.end() and st.find(q+p+r+pre[x-1])!=st.end()){
            cout << "Yes" << endl;
            return ;
        }
	}
    cout << "No" << endl; 
}

signed main()
{
	sensei();
	return 0;
}

T4 (ABC 267)D - Index × A(Not Continuous ver.)

/*
	题目含义:
		给你一个长度为n的数组a
		你需要在里面找到一个长度为m的子序列b
		并且 sigma(bi*i) 最大
*/

/*
	题解:
		这题相对于上一题来说,他的数据范围变小了
		M和N都在2000以内
		因此可以考虑一个O(N^2)的做法
		所以我们会考虑能不能dp
		
		定义一个数组 f[][]表示状态
		f[i][j] 表示在前i个数里选j个数组成b的最大值
		状态转移:
			f[i][j] = max(f[i-1][j-1]+a[i]*j,f[i-1][j]);
			
		
*/


inline void sensei()
{
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1);
	vector<vector<int>> f(2005, vector<int>(2005, -inf_ll));
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 0; i <= n; i++) {
		f[i][0] = 0;
	}

	for (int i = 1; i <= n; i++) {
		for (int j = 1;j <= m; j++) {
        	if(j <= i )
                f[i][j] = max(f[i - 1][j - 1] + a[i] * j, f[i - 1][j]);
		}
	}
	cout << f[n][m];
}

signed main()
{
	sensei();
	return 0;
}

T5: (CF TON ROUND(DIV1+DIV2)) B. Luke is a Foodie

/*
	题解: 当找到一个区间的最大值和最小值之差大于2*x,cnt++
*/
inline void sensei()
{
    int n,x;
    cin >> n >> x;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    
    int cnt = 0;
    int alls = 2*x;
    int minn = a[1];
    int maxn = a[1];
    
    for(int i=2;i<=n;i++){
        if(a[i] > maxn){
            maxn = a[i];
        }
        if(a[i] < minn){
            minn = a[i];
        }
        if(maxn - minn > alls) {
            cnt ++;
            minn = a[i];
            maxn = a[i];
        }
    }
    cout << cnt << endl;
}

signed main()
{
    int t;
    cin >> t;
    while(t --){
        sensei();
    }
    return 0;
}

T6 (CF ROUND 795 DIV.2)C. Sum of Substrings

/*
	题目描述:
		题目的大概意思就是
		给你一个只包含0和1的字符串s
		定义f(s) 为这个字符串每两个连续字符代表的十进制的和
		现在你有k次操作去换任意两个相邻字符
		输出f(s)可能的最小值
*/


/*
	题解: 
		贪心即可
		通过观察我们发现
		字符串里面除了第一个字符和最后一个字符出现了'1'  其他地方出现了1 必定对f(s)贡献了11
		而如果我们把某个不是在最后的字符移到了最后,那么 f(s) -= 10
		如果我们把某个不是第一的字符移动到了第一那么f(s) -= 1
		因此我们需要贪心,先考虑能不能移到最后,再考虑能不能移到第一
		注意如果字符串本身全为0那么直接输出0即可

*/



inline void sensei()
{
    int n,k;
    cin >> n >> k;
    int cnt = 0;
    string s = "";
    cin >> s;
    s = " " + s;
    for(int i=1;i<=n;i++){
        if(s[i] == '1'){
            cnt++;
        }
    }
    if(cnt == 0){
        cout << 0 << endl;
        return ;
    }
    int ans = 11*cnt;
    int st,ed;
    st = ed = 0;
    for(int i=1;i<=n;i++){
        if(s[i] == '1'){
            st = i;
            break;
        }
    }

//   debug(s.size());
    for(int i=n;i>=1;i--){
        if(s[i] == '1'){
            ed = i;
            break;
        }
    }
    
    if(st!=ed and st-1+n-ed<=k){
        ans -= 11;
    }else if(k>=n-ed){
        ans -= 10;
    }else if(k>=st-1){
        ans -= 1;
    }
    cout << ans << endl;
    
}

signed main()
{
    fuckios
    int t;
    cin >> t;
    while(t --){
        sensei();
    }
    return 0;
}


T7 (ABC 265)E - Warp

/*
	题目大意:
		先给你两个整数 n,m 表示你可以操作n次并且有m个障碍物
		然后给出六个整数分别代表A B C D E F 
		你每次操作有三种选择:
		1. 让你的坐标变为  (x+A,y+B)
		2. 让你的坐标变为  (x+C,y+D)
		3. 让你的坐标变为  (x+E,y+F)
		
		问:n次操作后,有多少种不同的路径
		对结果模上998244353
*/

/*
	题解,根据数据范围可以先想到dp
	定义f[i][j][k] 表示 
	操作一用了i次 
	操作二用了j次
	操作三用了k次 
	所造成的不同的路径数
	
	状态转移见代码
*/


const int p = 998244353;
 
int f[N][N][N];
/*
    f[i][j][k]
        表示 操作1用了i次
        操作2用了j次
        操作3用了k次
*/
 
inline void sensei()
{
	set<node> st;
	int n, m, ans = 0;
	cin >> n >> m;
	int A, B, C, D, E, F;
	cin >> A >> B >> C >> D >> E >> F;
	for (int i = 1; i <= m; i++) {
		int xx, yy;
		cin >> xx >> yy;
		st.insert(node(xx, yy));
	}
	f[0][0][0] = 1;
	for (int i = 0; i <= n; i++) {
		for (int j = 0; j <= n; j++) {
			if (i + j > n) continue;
			for (int k = 0; k <= n; k++) {
				if (i + j + k > n ) continue;
				if (i == 0 and j == i and k == i) {
					continue;
				}
				int x = i * A + j * C + k * E;
				int y = i * B + j * D + k * F;
				if (st.find(node(x, y)) != st.end()) {
					f[i][j][k] = 0;
					continue;
				}
				if (i) {
					f[i][j][k] = (f[i - 1][j][k] + f[i][j][k]) % p;
				}
				if (j) {
					f[i][j][k] = (f[i][j - 1][k] + f[i][j][k]) % p;
				}
				if (k) {
					f[i][j][k] = (f[i][j][k - 1] + f[i][j][k]) % p;
				}
				if (i + j + k == n) {
                    ans = (ans + f[i][j][k])%p;
				}
			}
		}
	}
    cout << ans << endl;
}
 
signed main()
{
	sensei();
	return 0;
}

快1点了。。。写不动了。。。休息一下。。明天继续

posted @ 2022-09-14 00:16  coolJazz  阅读(19)  评论(0)    收藏  举报