cf dp 2000分 乱刷

cf1680e

Moving Chips

// https://codeforces.com/problemset/problem/1680/E
#include<bits/stdc++.h>
using namespace std;

void fileio()
{
  //#ifdef LGS
  freopen("in.txt","r",stdin);
  freopen("out.txt","w",stdout);
  //#endif
}

const int N = 2e5 + 10;
int mp[2][N];
int dp[2][N]; // dp[0/1][i] clear 前 i-1 列 到达 (i,0/1);
int n;

void solve()
{
   cin >> n; for(int i = 1;i <= n;i ++) dp[0][i] = dp[1][i] = 0;
   
   for(int i = 0;i < 2;i ++) for(int j = 1;j <= n;j ++)
   {
      char c; cin >> c; mp[i][j] = (c == '*');
   }

   int l = 1;int r = n;
   while(mp[0][l] == 0 && mp[1][l] == 0) l++;
   while(mp[0][r] == 0 && mp[1][r] == 0) r--;
   for(int i = l;i <= r;i ++)
   {
      dp[0][i] = min(dp[0][i-1] + 1 + mp[1][i], dp[1][i-1] + 2);
      dp[1][i] = min(dp[1][i-1] + 1 + mp[0][i], dp[0][i-1] + 2);
   } 
   cout << min(dp[0][r],dp[1][r])-1 << endl;
}

int main()
{  
    fileio();
    int _; cin >> _;
    while(_--) solve();
}

cf1312e

array shrinking

dp[l][r] 表示 从l到r 合并区间后 长度的最小值;
w[l][r] 表示 sum of l ~ r

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;

const int N = 510;
int n;

int a[N];
int dp[N][N];
int w[N][N];

void fileio()
{
  //#ifdef LGS
  freopen("in.txt","r",stdin);
  freopen("out.txt","w",stdout);
  //#endif
}

void solve(){
    memset(dp,10000,sizeof dp);
    cin >> n; 
    for(int i = 1;i <= n;i ++){ cin >> a[i];dp[i][i]= 1; w[i][i] = a[i];}
    for(int len = 2;len <= n; len ++)
    for(int l = 1;l + len - 1 <= n;l ++){
        int r = l + len - 1;
        for(int mid = l;mid < r;mid ++)
        {
            dp[l][r] = min(dp[l][r], dp[l][mid] + dp[mid + 1][r]);
            if(dp[l][mid] == dp[mid + 1][r] && dp[l][mid] == 1 && w[l][mid] == w[mid + 1][r])
            dp[l][r] = 1,w[l][r] = w[l][mid] + 1;
        }
    }
    cout << dp[1][n] << endl;
  
}

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    //fileio();
    solve();
}

cf1257e

the contest

题意,三个集合abc,合起来不重不漏覆盖1n
每一次操作可以将一个数从一个集合移到另外的一个集合。
问需要几次操作使得集合a的所有元素 < b中所有元素 < c中所有元素。
集合可以变成空集合。
稍微想一下,会发现,a,b,c可以直接sort一下。

考虑两个集合的情况
假设样例

1 2 3 5
4 6

观察一下可以将4移上去或者将5移动下来;我们发现有坑这种结构;
对于a数组,我们每个数字的坑就是value - postion 即 a[i] - i;

我们再随机造一个复杂的样例

1 3 5 6 7 9 10
2 4 8 11 12


1 (2) 3 (4)5 6 7 (8) 9 10

选定一个位置 i a[i]之后的所有数移动到其他数列的代价是 lena - i 使i之前的数列合法的代价是 a[i]-i;
一旦 a 合法,b连锁合法。
所以res 等于 min(lena - i + a[i] - i) for(i from 1 to lena)

然后看abc的情况

cf1582e

Pchelyonok and Segments

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

void fileio()
{
  //#ifdef LGS
  freopen("in.txt","r",stdin);
  //freopen("out.txt","w",stdout);
  //#endif
}

const int N = 1e5 + 10;
const int M = 550;
const int INF = 0x3f3f3f3f;

int n;
int a[N];
int sum[N];
int dp[M][N];

void solve()
{   
   cin >> n;
   for(int i = 1;i <= n;i ++) cin >> a[i];
   for(int i = 1;i <= n;i ++) sum[i] = (sum[i-1]+a[i]);
   for(int k = 1;k <= 500;k ++) for(int i = 0;i <= n + 5;i ++) 
   dp[k][i] = 0;
   for(int i = 0;i <= n + 1;i ++) dp[0][i] = INF;
   
   for(int i = n ;i >= 1;i --) for(int k = 1;k <= 500;k ++)
   {
    dp[k][i] = dp[k][i + 1]; 
    // i 是枚举考虑到 第i个位置 k是当前枚举到第k个区间,区间长度也为k
    // dp的值是 表示第k个区间区间和的最大值
    if(i + k - 1 <= n && sum[i + k - 1] - sum[i - 1] < dp[k-1][i+k])// 合法转移
    dp[k][i]=max(dp[k][i],sum[i+k-1]-sum[i-1]);
   }
   //int res = 1;
   for(int i = 500;i >= 1;i --) if(dp[i][1]) {cout << i << endl; return;}
   cout << 1 << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    //fileio();
    int T;cin >> T;
    while(T --)solve();   
    //solve();
}

cf1516c

Baby Ehab Partitions Again

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

void fileio()
{
  //#ifdef LGS
  freopen("in.txt","r",stdin);
  //freopen("out.txt","w",stdout);
  //#endif
}

const int N = 110;
const int M = 2e5 + 20;

bool dp[M];
int a[N];
int n;

inline int gcd(int a,int b)
{
  return b ? gcd(b,a%b) : a;
}

void solve()
{   
  cin >> n; for(int i = 1;i <= n;i ++) cin >> a[i];
  memset(dp,false,sizeof dp); dp[0] = true;
  
  int GCD = 0; int sum = 0;
  for(int i = 1;i <= n;i ++) GCD = gcd(GCD,a[i]);
  //for(int i = 1;i <= n;i ++) sum += a[i];
  for(int i = 1;i <= n;i ++) a[i] /= GCD, sum += a[i];

  for(int i = 1; i <= n; i ++ )for(int j = M - 10; j >= a[i]; j -- )
  dp[j] = dp[j - a[i]] ? true : dp[j];

  //cout << sum/2 << endl;
  //cout << dp[sum/2] << endl;
  if(sum % 2 == 0 && dp[sum/2])
  {
    cout << 1 << endl;
    for(int i = 1;i <= n;i ++) if(a[i]&1) {cout << i << endl;return;}
  }
  else cout << 0 << endl;

}

signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    //fileio();
    int T = 1;//cin >> T;
    //while(T --)solve();   
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值