3.3-3.9 周记

3.3-3.10

1. NIM游戏

百度链接:https://baike.baidu.com/item/Nim%E6%B8%B8%E6%88%8F/6737105?fr=aladdin

定义:

  • P局面:先手必败
  • N局面:先手必胜

P局面的所有子局面都是N局面。N局面的子局面中必有一个是P局面

性质:\(a_1 \ xor \ a_2 \ xor \cdots xor \ a_n = 0\) 则为P局面

证明:

若某个局面异或结果大于0,则一定存在一个操作使得\(a_1 \ xor \ a_2 \ xor \cdots xor \ a_n = 0\)

若某个局面异或结果等于0,则一定不存在一个操作使得\(a_1 \ xor \ a_2 \ xor \cdots xor \ a_n = 0\)

因为若Nim和为X,X得二进制表示最左边的1在第k位,则一定存在一个该位为1的堆。设这堆火柴数量为Y,则只需把它拿成 Z = Y xor X 根火柴,得到的状态就是必败状态。

2. chomp!游戏

m*n的棋盘,每次取走一个方格并拿掉它右边和上面的所有方格。拿到(1,1)的人输。

先手必胜,因为先手可以在后手先一步达到必胜状态。

3. SG函数

SG(x) = mex(S)

4. 动归复习

1. LCIS

求两个序列的最长公共上升子序列

d[i][j]表示A的前i个与B的前j个,并且以\(B_j\)为结尾的LCIS长度。为啥一定要带这个结尾信息呢?因为进行下一次拼接时,必须知道结尾信息,否则不能满足上升关系。

  • A[i] != B[j]时,d[i][j] = d[i-1][j]
  • A[i] == B[j]时,\(d[i][j] = max_{\{1\le k<j, B_k<A_i\}} {d[i-1][k]}+1\)
#include <bits/stdc++.h>
using namespace std;
int n;
int A[3030],B[3030];
int d[3030][3030];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&A[i]);
    for(int i=1;i<=n;i++)scanf("%d",&B[i]);
    int ans = 0;
    for(int i=1;i<=n;i++){
        int val = 0;
        for(int j=1;j<=n;j++){
            if(B[j] == A[i]){
                d[i][j] = val+1;
            }
            else d[i][j] = d[i-1][j];
            if(B[j]<A[i]) val = max(val,d[i-1][j]);
            ans = max(ans,d[i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

2. POJ-3666

$S = |A_1?-?B_1| + |A_2?-?B_2| + ... + |A_N?-?B_N?| $

给出A数组,求一个不下降或者不上升的B数组,使得S值最小

可以猜到的是,B数组中的所有元素都在A中出现过。(数学归纳法可以证明,但也要靠直觉)

然后既然A来自B,那么也就是说可以先把A复制一份,然后从中选某些数字,进而得到B。

\(d[i][j]\) 表示A数组的前 i 个,当以\(B_j\)结尾时,S的最小值

\(d[i][j] = min_{1\le k\le j} d[i-1][k] + abs(A[i]-B[j])\)

其中B必须先离散化,随着j有序之后才可以。

ll a[2010],b[2010],d[2010];
int n;
ll abs(ll a){
    return a>0?a:-a;
}
ll dp()
{
    for(int i=1;i<=n;i++)
        d[i] = abs(a[1]-b[i]);
    for(int i=2;i<=n;i++)
    {
        ll mi = d[1];
        for(int j=1;j<=n;j++)
        {
            mi = min(mi,d[j]);
            d[j] = mi + abs(a[i]-b[j]);
        }
    }
    ll ans = d[1];
    for(int i=2;i<=n;i++)
        ans = min(ans,d[i]);
    return ans;
}
bool cmp(ll a,ll b)
{
    return a>b;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        b[i] = a[i];
    }
    sort(b+1,b+1+n);
    ll ans = dp();
    sort(b+1,b+1+n,cmp);
    ans = min(ans,dp());
    cout<<ans<<endl;
    return 0;
}

3. CH-5102 Mobile Service

三个员工在1,2,3。

要求按照p序列,必须有一个员工到达对应位置。求最少距离。要求一个地方不能有两个员工。

很容易想到$d[i][x][y][z] $ 表示当前为p[i],三个员工为x,y,z位置时的最少花费。

但是该算法规模为 \(1000*200^3\) 故不能承受。

但是考虑到 i 时刻,必然有一个员工在p[i]位置。所以可以节约一维。另外转移的时候一定要注意,不能有两个人在同一个地方

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int cost[220][220];
int L,n,p[1010];
int d[1010][220][220];
int main(){
    cin>>L>>n;
    for(int i=1;i<=L;i++)
        for(int j=1;j<=L;j++)scanf("%d",&cost[i][j]);
    for(int i=1;i<=n;i++)scanf("%d",&p[i]);
    p[0] = 1;
    memset(d,0x3f,sizeof d);
    d[0][2][3] = 0;
    for(int i=0;i<n;i++){
        for(int j=1;j<=L;j++){
            for(int k=1;k<=L;k++){
                if(p[i+1]!=j&&p[i+1]!=k)
                d[i+1][j][k] = min(d[i+1][j][k],d[i][j][k] + cost[p[i]][p[i+1]]);
                if(p[i+1]!=k&&p[i+1]!=p[i])
                d[i+1][p[i]][k] = min(d[i+1][p[i]][k],d[i][j][k] + cost[j][p[i+1]]);
                if(p[i+1]!=j&&p[i+1]!=p[i])
                d[i+1][j][p[i]] = min(d[i+1][j][p[i]],d[i][j][k] + cost[k][p[i+1]]);
            }
        }
    }
    int res = inf;
    for(int i=1;i<=L;i++)
        for(int j=1;j<=L;j++){
            if(i!=p[n]&&j!=p[n])
            res = min(res,d[n][i][j]);
        }
    cout<<res<<endl;
    return 0;
}

4. CH-5103 传纸条

d[i][x1][x2] 表示走了 i 步,一条路径在x1,一条路径在x2时的最大权值和

#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[55][55];
int d[110][55][55];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
    d[0][1][1] = a[1][1];
    for(int i=0;i<n+m-2;i++){
        for(int x1 = 1;x1<=1+i&&x1<=n;x1++){
            for(int x2 = x1;x2<=1+i&&x2<=n;x2++){
                int y1 = i+2-x1;
                int y2 = i+2-x2;
                if(y1>m||y2>m)continue;
                d[i+1][x1][x2+1] = max(d[i+1][x1][x2+1],d[i][x1][x2]+a[x1][y1+1]+a[x2+1][y2]);
                if(x1==x2){
                    d[i+1][x1][x2] = max(d[i+1][x1][x2],d[i][x1][x2]+a[x1][y1+1]);
                    d[i+1][x1+1][x2+1] = max(d[i+1][x1+1][x2+1],d[i][x1][x2]+a[x1+1][y1]);
                }
                else{
                    d[i+1][x1][x2] = max(d[i+1][x1][x2],d[i][x1][x2] + a[x1][y1+1]+a[x2][y2+1]);
                    d[i+1][x1+1][x2+1] = max(d[i+1][x1+1][x2+1],d[i][x1][x2]+a[x1+1][y1]+a[x2+1][y2]);
                    if(x1==x2-1){
                        d[i+1][x1+1][x2] = max(d[i+1][x1+1][x2],d[i][x1][x2]+a[x1+1][y1]);
                    }
                    else d[i+1][x1+1][x2] = max(d[i+1][x1+1][x2],d[i][x1][x2]+a[x1+1][y1]+a[x2][y2+1]);
                }
            }
        }
    }
    cout<<d[n+m-2][n][n]<<endl;
    return 0;
}

5. CF-1118

D2 - Coffee and Coursework (Hard Version)

  • 很容易想到的二分,在一个处理上面卡壳了
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long ll;
int n,m;
ll a[N],b[N];
bool cmp(ll a,ll b){return a>b;}
bool check(int mid){
    ll sum = 0;
    for(int i=0;;i++){
        if(mid+i*mid<=n&&a[mid+i*mid]>=i){
            sum += b[(i+1)*mid] - b[i*mid] - i*(mid);
        }
        else{
            int index;
            for(index = i*mid+1;index<=n&&index<=(i+1)*mid;index++)
                if(a[index]<=i)break;
            sum += b[index-1]-b[i*mid]-i*(index - i*mid -1);
            break;
        }
    }
    return sum>=m;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        b[i] = b[i-1]+a[i];
    }
    int l = 1,r = n;
    while(l<r){
        int mid = (l+r)/2;
        if(check(mid))r = mid;
        else l = mid+1;
    }
    if(check(r))
        cout<<r<<endl;
    else cout<<-1<<endl;
    return 0;
}

6. CF-1121

C - System Testing

  • 烦人的模拟,一开始理解错题意了,看题这种事情实在是不能马虎
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m;
int now[110],a[1010],pre[110],now_id[110],has[1010];
int round(int x,int y){
    return (int)((double)x*100/y+0.5);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    priority_queue< pair<int,int> > q;
    int num = 0;
    for(int i=1;i<=m;i++){
        now[i] = a[i];
        pre[i] = 1;
        now_id[i] = i;
        q.push(make_pair(-a[i],i));
    }
    int now_time = 0;
    int res = 0,t = m;
    for(int now_time = 1;now_time<=150*1000;now_time++){
        for(int i=1;i<=m;i++){
            if(now[i]<now_time){
                num++;
                if(t<n){
                    now[i] += a[++t];
                    pre[i] = now_time;
                    now_id[i] = t;
                }
                else{
                    now[i] = inf;
                    pre[i] = inf;
                }
            }
        }
        int rou = round(num,n);
        for(int i=1;i<=m;i++){
            if(now_time-pre[i]+1==rou){
                has[now_id[i]] = 1;
            }
        }
        if(num == n)break;
    }
    for(int i=1;i<=n;i++)if(has[i])res++;
    cout<<res<<endl;
    return 0;
}

7. CF-1036

C - Classy Numbers

  • 组合数
  • 寻思了挺久,不过1A。大概还是用到了部分递推。函数写了一堆
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll L,R;
int T;
ll C[20][20];
ll A[20][20];
ll po[20];
//初始化组合数和10的n次方
void init(){
    C[0][0] = 1;
    for(int i=1;i<=18;i++){
        C[i][0] = 1;
        for(int j=1;j<=i;j++){
            C[i][j] = C[i-1][j-1] + C[i-1][j];
        }
    }
    po[0] = 1;
    for(int i=1;i<=18;i++)po[i] = po[i-1]*10;
}
//计算某个数长度
int calc_len(ll x){
    int len = 0;
    while(x){
        x/=10;len++;
    }
    return len;
}
//计算某个数的头位有多大
int calc_left(ll x){
    while(x>=10)x/=10;
    return x;
}
ll calc(ll x,ll num){
    if(num==0)return 1;
    ll len = calc_len(x);
    ll max_left = calc_left(x);
    //printf("%lld %lld %lld %lld\n",x,len,max_left,num);
    ll res = 0;
    for(int i=num-1;i>=0;i--){
        res += (max_left-1)*C[len-1][i]*A[9][i];
    }
    for(int i=num;i>=0;i--)
        res += C[len-1][i]*A[9][i];
    //printf("%lld %lld\n",x,res);
    res += calc(x-max_left*po[len-1],num-1);
    return res;
}
int main(){
    init();
    A[9][0] = 1;A[9][1] = 9;A[9][2] = 81;A[9][3] = 729;
    cin>>T;
    while(T--){
        cin>>L>>R;
        //printf("calc(R,3):%lld,calc(L,3):%lld\n",calc(R,3),calc(L,3));
        ll res = calc(R,3)-calc(L-1,3);
        printf("%lld\n",res);
    }
    return 0;
}
  • 方法二:先把所有满足要求的数字求出来,然后二分划定区间。可以求出这样的数字不是特别多 $910^2 A_{18}^3 = 4406400 $
#include <bits/stdc++.h>

#define forn(i, n) for (int i = 0; i < int(n); i++)

using namespace std;

vector<long long> res;
//可以说非常巧妙了
void brute(int pos, int cnt, long long cur){
    if (pos == 18){
        res.push_back(cur);
        return;
    }

    brute(pos + 1, cnt, cur * 10);

    if (cnt < 3)
        for (int i = 1; i <= 9; ++i)
            brute(pos + 1, cnt + 1, cur * 10 + i);
}

int main() {
    brute(0, 0, 0);
    res.push_back(1000000000000000000);

    int T;
    scanf("%d", &T);
    forn(i, T){
        long long L, R;
        scanf("%lld%lld", &L, &R);
        printf("%d\n", int(upper_bound(res.begin(), res.end(), R) - lower_bound(res.begin(), res.end(), L)));
    }
    return 0;
}

8. CF-1132

C - Painting the Fence

  • 第一眼没看出来是个可以暴力的的题目
#include <bits/stdc++.h>
using namespace std;
int n,q;
int a[5010],b[5050],c[5050];
struct node{
    int l,r;
}k[5050];
bool cmp(node x,node y){
    if(b[x.r]-b[x.l-1]==b[y.r]-b[y.l-1]){
        return x.r-x.l<y.r-y.l;
    }
    return b[x.r]-b[x.l-1]<b[y.r]-b[y.l-1];
}
int main(){
    cin>>n>>q;
    for(int i=1;i<=q;i++){
        scanf("%d%d",&k[i].l,&k[i].r);
        a[k[i].l]++;
        a[k[i].r+1]--;
    }
    int res = 0;
    for(int i=1;i<=n;i++){
        a[i] += a[i-1];
        if(a[i]!=0)res++;
        b[i] += b[i-1] + (a[i]==1?1:0);
        c[i] += c[i-1] + (a[i]==2?1:0);
        //printf("%d ",c[i]);
    }
    int mi = 0x3f3f3f3f;
    for(int i=1;i<=q;i++){

        for(int j=i+1;j<=q;j++){
            int cnt = 0;
            int r = min(k[i].r,k[j].r);
            int l = max(k[i].l,k[j].l);
            cnt += b[k[i].r]-b[k[i].l-1] + b[k[j].r]-b[k[j].l-1];
            if(r>=l) cnt += c[r]-c[l-1];
            mi = min(mi,cnt);
        }
    }
    cout<<res-mi<<endl;
    return 0;
}
  • CF给的教程是枚举每个 i ,然后统计出除 i 之外最优解。然后整体取最优解。

F - Clear the String

  • 区间dp
#include <bits/stdc++.h>
using namespace std;
int n;
char s[550];
int d[550][550];
int main(){
    cin>>n;
    scanf("%s",s+1);
    memset(d,0x3f,sizeof d);
    for(int i=1;i<=n;i++)d[i][i] = 1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++){
            for(int k=j;k<i;k++){
                if(k==i-1){
                    if(s[k]==s[i])d[j][i] = min(d[j][i],d[j][k]);
                    else d[j][i] = min(d[j][i],d[j][k]+1);
                    continue;
                }
                if(s[k] == s[i]){
                    d[j][i] = min(d[j][i],d[j][k]+d[k+1][i-1]);
                }
                else d[j][i] = min(d[j][i],d[j][k]+d[k+1][i-1]+1);
            }
            //printf("%d %d %d\n",j,i,d[j][i]);
        }
    }
    cout<<d[1][n]<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/1625--H/p/10499651.html

时间: 2024-11-09 09:43:29

3.3-3.9 周记的相关文章

第4周~第12周周记

因为之前没注意到有周记这回事,所以在这里一并补上,本周是第12周,也一并写在这里,请老师见谅 第四周:入学的第四周,整个人的重心才刚刚开始往学习上转,开始逐渐摆脱了放假回来的那种感觉,逐渐步入学习状态了,但是心还是定不下来,没办法全身心的投入打代码当中去. 第五周:状态相对于上一周会好一些了,但是由于系队又开始组织训练了,耽误了不少时间,一周下来也没学多少东西进去,完全不知道重心该放在什么地方了. 第六周:因为临近球赛了,所以我决定暂时先配合球队训练,落下来的学习内容之后几周慢慢补上. 第七周:

第七周周记

第七周周记: 本周完成了 1.学习了高数的隐函数的求导和多元函数的求导,复习了偏导数和全微分. 2.学习了数据结构的顺序表和链式表的动态存储和应用,以及如何写代码. 3.HTML的网页设计:关于’滚动页面’的页面设计和开始学习用全代码做网页. 4.学会了在配置中设置网关,用命令行写配置和绘制一张交换机网络拓扑图. 5.再读了一本外国著作. 希望能够做好眼前事儿好好复习准备半期考,把以前落下的知识补回,更刻苦一点学习早日把知识掌握好. 周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文

第四周周记

转眼过了半个学期,又要准备期中了.看着同学们都以良好的态度去学习,而自己的心还没平静下来,学习上太过放纵.是时候收回浮躁的学习态度,预备期中考同时也更正自己的学习态度. 这周就在晃神中度过,仿佛什么都没收获到,但在写这篇周记时又有了感悟.我觉得吧在享受娱乐休闲之后,自己的自觉性要去自己去安心的学习,学的时候不要想着玩,在玩的时候玩痛快,学的时候后学认真,要心甘情愿的学习,才能把习学好,把学习当成生命中的习惯,用心去完成而不是应付.

工作周记 - 第四周 (2016/06/12 - 2016/06/18) 我没喝多,但是今天话多了 - -

- -|||... 这周上了七天班啊有木有 1.团队组建完毕,虽然不是一个很庞大的团队,但是有人能做事,每天充分利用好8个小时,彼此互相帮助就可以作为一个强大的团队来支撑公司 团队并不需要那些每天上下班打个卡,有任务就做,没任务就上网的那种,这样的员工见多了,曾经我待过一家所谓的大公司,在旁人眼里,这公司有多好多少,老板在外面随便开个会就能拿几个亿的风投,但是呢,你做的爽吗,你做的舒服吗,里面的员工都是老油条,你请教问题不理你,还赶你走,给你脸色看,包括的你经理,从来不鸟你,问问题也不睬你,事不

第九、十周周记

第九.十周周记: 这两周完成了 1.学习了JavaScript网页设计,学习了更多的代码,网页设计更有趣了,掌握全代码方式的设计,掌握了更多的功能等. 2.学习了数据结构的树与二叉树,以及如何写代码. 3.学会了绘制计算机网络基础的代码设置等. 希望能够加倍努力,收获成长.Don't lose your heart,never give up. 周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文方面的学习 知识技能总结 第 五 周 学习JavaScript网页设计,学习了更多的代码,

周记3

web网页,老师叫我们自己做一个游戏,还挺好玩.当游戏做出来的时候,很开心.虽然有点累不过代码敲完的那种成就感还是很强的.说实在前几周周记都是一些心灵鸡汤,一点实际都没有.这就跟我们现在的状态一样.就是嘴巴上讲一讲,一点实际都没有.其实最主要的原因还是因为我们懒惯了,这种懒就像是瘟疫一样会在每个学生身上传播.个人没有写日记,周记的习惯.因为我觉得有些东西还是埋在心里更好.周记这类更适合想于表达的人,表达自己的想法.说写一点技术性的东西,但是其实我并不喜欢.去学一个自己不喜欢的东西,真的很难. 这

周记5

周记5 周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文方面的学习 知识技能总结 5 学习并掌握好C语言程序结构中的线性表应用以及课后练习打线性存储代码以及HTML网页设计 本学期专业课程中,利用周末以及没课这类非课堂时间,学习时间的总结. 单链表顺序存储以及线性表应用 发表<世界是数字的>读后感 阅读<语言与文化> 对一周以来,我通过学校课堂.业余自学.慕课.社团活动中,所学习到的如何设置一个网页开篇.以及从慕课网学习PS入门,熟练C语言数据结构线性表应用

五月第一周周记

写在前面 It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spri

[GLSL]着色器周记01!

我决定开个新坑了.以后每周五更新.这是GLSL的学习周记!GLSL就是OPENGL SHADER LANGUAGE的简称,就是着色器语言.着色器是一种交给显卡运行的小程序,这种小程序可以用GLSL来写,写好后交给OPENGL编译,就可以在显卡上运行了. 那么问题来了!为什么要给显卡运行呢?显卡是一种特殊的处理器,有核心,有寄存器,还有内存,不过对比CPU,最大的特点就是显卡的核心更多.多多少呢?一般CPU有4-8个核心,而显卡则是100个左右的核心!不过由于造价还有空间的限制,显卡的某些功能会被

[周记]8.7~8.16

决定拾起初中还在用sina blog时的习惯,用周记记录一下刷题进程. 这周是在金中集训(夏令营),与众多大佬坐在同一个机房中确实是诚惶诚恐. 平时的学习还有提升主要分为两部分吧,一是建好数学模型和找对算法,二是实现.前者靠打比赛,后者靠刷题和代码量 [比赛] 5场(ST)SRM+洛谷1场民间noip模拟赛+1场atcoder(beginner) srm让我看到差距,从考场心态到代码能力 最重要的一点: 不要怕 想到了就去写 先打完暴力然后拿去对拍... 洛谷那场打一半就没了,写了一道uoj上很