洛谷P3694 邦邦的大合唱站队/签到开

noip好难呀。

P3694 邦邦的大合唱站队/签到开

达到一个感觉到来接触长了,重开一个。

题目背景

BanG Dream!里的具有偶像乐队要同步大合唱,不过以排队齐发生了有些题目。

36.Vigenère 密码

问题叙述

N个偶像排成一列,他们自M个不同的乐队。每个组织至少发生一个偶像。

本要求还配置行,使来同一乐队的偶像连续的站于齐。重新部署的计是,让多少偶发像出列(剩下的偶像不动),然后给出列的偶像一个个归队到原的空位,归队的职任意。

借问最少为多少偶像出列?

   
粘个Openjudge上之代码

输入输出格式

输入格式:

 

第一行2个整数N,M。

通下N个执行,每行一个整数a_i(1\le a_i \le M)ai​(1≤ai​≤M),表示队列中第i独偶像的集体编号。

 

输出格式:

 

一个平头,表示答案

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include <cstdlib>
#include <algorithm>
#include <iomanip>
using namespace std;
char a[101],s[1001],b[1001];
int c[1001],j;
int main()
{
    int la,ls,i,j;
    gets(a);
    gets(s);
    la=strlen(a);
    ls=strlen(s);

    for(i=0;i<la;i++)
    {if(a[i]<=90)
    a[i]=a[i]+32;}

    for(i=0;i<la;i++)
    c[i]=a[i]-97;

    for(i=0;i<ls;i++)
    c[i+la]=c[i];


    for(i=0;i<ls;i++)
    {
    b[i]=s[i]-c[i];
    if((s[i]>=65&&b[i]<65)||(s[i]>=97&&b[i]<97))
    b[i]=b[i]+26;
    }     
    puts(b);
    return 0;
}

输入输出样例

输入样例#1: 复制

12 4
1
3
2
4
2
1
2
3
1
1
3
4

输出样例#1: 复制

7

 

说明

【样例解释】

1  3   √
3  3
2  3   √
4  4
2  4   √
1  2   √
2  2
3  2   √
1  1
1  1
3  1   √
4  1   √

【数据规模】

对于20%的数据,N\le 20,
M=2N≤20,M=2

对于40%的数据,N\le 100,
M\le 4N≤100,M≤4

对于70%的数据,N\le
2000, M\le 10N≤2000,M≤10

对于所有多少,1\le N\le
10^5, M\le 201≤N≤105,M≤20

图片 1图片 2

#include<cstdio>
const int N=100005,M=26;
int a[N],b[M],n,m,s[M],sum[M][N],ans=1<<30;
bool vis[M];
void dfs(int i, int tot){
    if(i>n){
        if(tot<ans) ans=tot;
        return;
    }
    if(tot>ans) return;
    for(int j=1;j<=m;j++)
        if(!vis[j]){
            vis[j]=true;
            dfs(i+s[j],tot+s[j]-sum[j][i+s[j]-1]+sum[j][i-1]);
            vis[j]=false;
        }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        s[a[i]]++;
    }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++){
            sum[i][j]=sum[i][j-1];
            if(a[j]==i) sum[i][j]++;
        } 
    dfs(1,0);
    printf("%d",ans);
}

70分 暴力

图片 3图片 4

/*
    状态压缩,dp[i]表示达到i状态出队的最小人数,sum[i][j]表示前i个人有几个属于j乐队那么枚举一个l,r则有dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+(r-l-(sum[r][j]-sum[l][j]))); 
*/
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,dp[(1<<20)+1],a[100010],sum[100010][21];
int main(){
    freopen("Cola.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);a[i]--;
        for(int j=0;j<m;j++){
            sum[i][j]=sum[i-1][j];
            if(a[i]==j)sum[i][j]++;
        }
    }
    for(int i=0;i<(1<<m);i++)dp[i]=0x7fffffff;dp[0]=0;
    for(int i=0;i<(1<<m);i++){
        int s=0;
        for(int j=0;j<m;j++)if(i&(1<<j))s+=sum[n][j];
        for(int j=0;j<m;j++){
            if(i&(1<<j))continue;
            int num=sum[n][j];
            int r=s+num,l=s;
            dp[i|(1<<j)]=min(dp[i|(1<<j)],(r-l-(sum[r][j]-sum[l][j])+dp[i]));
        }
    }
    printf("%d",dp[(1<<m)-1]);
}

100分 状压dp

 

37.国王游戏

   
贪心。手动艾特LLJ。

   
粘一个别人的代码。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int  n,i,sum[10000],kx,ky,t[10000],ans[10000];
struct node
{
    int x;
    int y;
}a[1001];//每个大臣的左右手数值 
bool cmp(node a,node b)
{
    return a.x*a.y<b.x*b.y;//按照左右手乘积排序 
}
bool judge()//用来判断当前大臣的结果是不是比ans大 
{
    int i;
    for (i=1;i<=t[0];++i)    
        if (t[i]>ans[i])
            return true;
        else
            if (t[i]<ans[i])
                return false;
    return false;
}
void mul(int x)//高乘 
{
    int g=0,i;
    for (i=1;i<=sum[0];++i)
    {
        sum[i]=sum[i]*x+g;
        g=sum[i]/10;
        sum[i]=sum[i]%10;
    }
    while  (g!=0)
    {
        ++sum[0];
        sum[sum[0]]=g%10;
        g/=10;
    }
}
void divv(int x)//高除,附带比较当前大臣答案和ans的大小关系 
{
    int num=0,i=sum[0]+1,s=0;
    memset(t,0,sizeof(t));
    while (num<x)
    {
        --i;
        num=num*10+sum[i];
    }
    t[0]=i;
    for (;i>=1;--i)
    {
        t[++s]=num/x;
        num=num%x*10+sum[i-1];
    }
    //高除,其中t保存当前大臣的结果 
    if (t[0]>ans[0]||t[0]==ans[0]&&judge())//.若比ans大则更新ans 
    {
        ans[0]=t[0];
        for (i=1;i<=t[0];++i)
            ans[i]=t[i];
    }
}
int main()
{
    cin>>n;
    cin>>kx>>ky;
    sum[1]=kx;
    sum[0]=1;
    ans[0]=1;
    ans[1]=0;
    //下标0保存长度
    //sum用来计算到第i个大臣的左手乘积 
    for (i=1;i<=n;++i)
        cin>>a[i].x>>a[i].y;
    sort(a+1,a+n+1,cmp);  
     for (i=1;i<=n;++i)
    {
        mul(a[i].x);
        divv(a[i].y*a[i].x);//因a[i].x当前已经乘过所以除的时候要再除一遍 
    }
      for (i=1;i<=ans[0];++i)
          cout<<ans[i];
}

 

38.同余方程

   
做不来,是免是没救了。。。

   
裸的壮大欧几里得。

   
注意扩欧先除还乘以免爆炸。。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
using namespace std;
typedef long long LL;
LL a,b,x,y,d;
void exgcd (LL a,LL b,LL &x,LL &y,LL &d) {
    if(!b) {d=a; x=1; y=0; return;}
    exgcd(b,a%b,y,x,d); y=y-(a/b*x);
}
int main()
{
    cin>>a>>b;
    exgcd(a,b,x,y,d);
    cout<<(x+b)%b<<endl;
    return 0;
}

  

39.借教室

   
第一目线段树模板,听说会让卡,卡卡常应该力所能及过吧。

    正解
二分+差分。

   
一始将有n写成m,一直WA第18单点。。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
int n,m,a[maxn],b[maxn],ll[maxn],rr[maxn],c[maxn];

void read(int &x) {
    char ch=getchar(); int ret=0,f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    x=ret*f;
}

void init() {
    read(n); 
    read(m);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=m;i++) { 
        read(c[i]);
        read(ll[i]);
        read(rr[i]);
    }
}

int ok(int x) {
    for(int i=1;i<=n;i++) b[i]=a[i]-a[i-1];
    for(int i=1;i<=x;i++) {
        int l=ll[i],r=rr[i];
        b[l]-=c[i];
        b[r+1]+=c[i];
    }
    int now=0;
    for(int i=1;i<=n;i++) {
        now+=b[i];
        if(now<0) return 0;
    }
    return 1;
}

void work() {
    int l=0,r=m,ans=0;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(!ok(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    if(!ans) printf("0\n");
    else {
        printf("-1\n");
        printf("%d\n",ans);
    }
}

int main()
{
    init();
    work();
    return 0;
}

  

40.津津的存款计划

   
Openjudge打不上马啊,随便抄个别人的代码和转。

#include <iostream>
using namespace std;
int main()
{
    const int m=300; 
    bool flag=true; 
    int h=0,s=0;
    int a;
    for(int i=1;i<13;i++) {
        cin>>a;
        h+=m; 
        if(h<a) {
            cout<<-i;
            flag=false;
            break;
        }
        int left=h-a; 
        h=left%100; 
        s+=left-h; 
    }
    if(flag) cout<<s*1.2+h;
    return 0;
}

 

 

41.集合果子

   
优先队列水过。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
const int maxn=10005;
using namespace std;
typedef long long LL;
int n,x,ok[maxn],ans;

void read(int &x) {
    char ch=getchar(); int ret=0,f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    x=ret*f;
}

priority_queue<int,vector<int>,greater<int> >que;

int main()
{
    read(n);
    for(int i=1;i<=n;i++) { 
        read(x);
        que.push(x);
    }
    while(!que.empty()) {
        int a=que.top();
        que.pop();
        if(que.empty()) break;
        int b=que.top();
        que.pop();
        ans+=a+b;
        que.push(a+b);
    }
    printf("%d\n",ans);
    return 0;
}

 

31.合唱队形

   
抄个代码和同道

#include<iostream>
#include<cmath>
using namespace std;
int num[1010];//每个人的身高 
int ans=1;//最后留下的人数 
int sum1[1010],sum2[1010];//升序列和降序列中留下的人数 
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
      cin>>num[i];//输入 
      sum1[i]=1;//留下的人数,至少为1 
      sum2[i]=1;}
    for(int i=1;i<=n;i++)
      for(int j=1;j<i;j++)
        if(num[i]>num[j])//如果i位置的值大于j位置的,这是可以作为上升子序列 
        sum1[i]=max(sum1[i],sum1[j]+1);//比较不取i位置和取i位置哪个留下的人多 
    for(int i=n;i>=1;i--)//最小降序列,反着枚举 
      for(int j=n;j>i;j--)
        if(num[i]>num[j])
        sum2[i]=max(sum2[i],sum2[j]+1);
    for(int i=1;i<=n;i++)
        ans=max(ans,(sum2[i]+sum1[i]-1));//ans是留下的人数,和每一种方案留下的人数比较。减一是中间的人重复计数。 
    cout<<n-ans<<endl;//n是总人数,ans留下的人数 
    return 0;
}

  

 32.统计数字 

   
同齐,装出自己开了写的金科玉律。

#include <iostream>
#include <algorithm>//快排头文件
using namespace std;
bool cmp (int a,int b)//养成写排序规则的好习惯
{
     return a<b;
}
int main ()
{
    int n;
    cin>>n;
    int a[n];
    for (int i=0;i<n;i++)
    cin>>a[i];
    sort (a,a+n,cmp);//进行升序排序
    int ans=1;//计数变量
    for (int i=1;i<n;i++)
    {
        if (a[i-1]==a[i]) ans++;//若两两相等,计数加一
        else {cout<<a[i-1]<<' '<<ans<<endl;ans=1;}//不等就输出,重新赋值
    }
    cout<<a[n-1]<<' '<<ans<<endl;//因为最后一个数字还未输出,所以输出
    return 0;
}

 

33.天天便于跑步

   
一发端看超级难写,然而写起竟之风调雨顺而一A了,就于开心。

 
  描绘得老大好之博客

   
这片上遇到不少差分,才察觉实际自己原先根本未晓差分到底是甚,差分真是神奇的事物。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
const int maxn=300000; 
using namespace std;
typedef long long LL;
int n,m,w[maxn],up[maxn<<1],dn[maxn<<1];
vector<int>vcu[maxn][2];
vector<int>vcd[maxn][2];

void read(int &x) {
    int ret=0,f=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    x=ret*f;
}

int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1];
void add(int u,int v) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}

int f[maxn][20],R[maxn];
void dfs1(int x,int fa) {
    f[x][0]=fa; R[x]=R[fa]+1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa){
        dfs1(to[i],x);
    }
}

void make_st() {
    for(int i=1;i<=19;i++)
        for(int x=1;x<=n;x++) {
            f[x][i]=f[f[x][i-1]][i-1];
        }
}

int get_lca(int x,int y,int &tp) {
    int fl=0;
    if(R[x]<R[y]) {fl=1; swap(x,y);}
    for(int i=19;i>=0;i--) 
        if(f[x][i]&&R[f[x][i]]>R[y]) 
            x=f[x][i];
    if(f[x][0]==y) {tp=x; return f[x][0];}
    if(f[x][0]&&R[f[x][0]]>=R[y]) x=f[x][0];
    for(int i=19;i>=0;i--) 
        if(f[x][i]&&f[x][i]!=f[y][i]) 
            x=f[x][i],y=f[y][i];
    if(fl) tp=x; else tp=y;
    return f[x][0];
}

void init() {
    read(n); read(m);
    for(int i=1;i<n;i++) {
        int u,v;
        read(u); read(v);
        add(u,v);
    }
    dfs1(1,0);
    make_st();
    for(int i=1;i<=n;i++) read(w[i]);
    for(int i=1;i<=m;i++) {
        int x,y,z,tp;
        read(x); read(y);
        z=get_lca(x,y,tp);
        int len=R[x]-R[z]+R[y]-R[z];
        vcu[x][1].push_back(R[x]);
        vcu[z][0].push_back(R[x]);
        if(y==z) continue;
        vcd[y][1].push_back(maxn+len-R[y]); 
        vcd[tp][0].push_back(maxn+len-R[y]); 
    }
}

int ans[maxn];
void dfs(int x,int fa) {
    int nup=w[x]+R[x],nd=w[x]-R[x]+maxn;
    int prup=up[nup],prd=dn[nd];
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        dfs(to[i],x);
    }
    for(int i=0;i<vcu[x][1].size();i++) {
        int tp=vcu[x][1][i];
        up[tp]++;
    }
    for(int i=0;i<vcd[x][1].size();i++) {
        int tp=vcd[x][1][i];
        dn[tp]++;
    }
    ans[x]+=(up[nup]-prup);
    ans[x]+=(dn[nd]-prd);
    for(int i=0;i<vcu[x][0].size();i++) {
        int tp=vcu[x][0][i];
        up[tp]--;
    }
    for(int i=0;i<vcd[x][0].size();i++) {
        int tp=vcd[x][0][i];
        dn[tp]--;
    }
}

void work() {
    dfs(1,0);
    for(int i=1;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
}

int main()
{
    init();
    work();
    return 0;
}

 

34.换教室

    期望dp.

   
dp[i][j][k]代表第i节课为止,共申请了j次,本次申请还是非申请的期望。

   
然后虽够呛好转移了,很好想念然写起较恶心,十分丧权辱国。

   
神奇的凡多少两单教室之间会用很多长条路你一旦抱最好小之。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
const int maxv=299+5;
const int maxn=2005;
using namespace std;
typedef long long LL;
int n,m,v,e,a[maxn],b[maxn];
double c[maxn],dp[maxn][maxn][2],d[maxv][maxv];

void init() {
    scanf("%d%d%d%d",&n,&m,&v,&e);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++) scanf("%lf",&c[i]);
    memset(d,127,sizeof(d));
    for(int i=1;i<=e;i++) {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        d[x][y]=min(d[x][y],(double)z);
        d[y][x]=d[x][y];
    }
}

void floyd() {
    for(int k=1;k<=v;k++)
    for(int i=1;i<=v;i++)
    for(int j=1;j<=v;j++) {
        if(i==j) d[i][j]=0;
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    }
}

void work() {
    floyd();
    memset(dp,127,sizeof(dp));
    dp[1][0][0]=0;
    dp[1][1][1]=0;
    for(int i=2;i<=n;i++) {
        int up=min(i,m);
        for(int j=0;j<=up;j++) {
            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+d[a[i-1]][a[i]]);
            if(j) {
            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][1]+
            d[a[i-1]][a[i]]*(1-c[i-1])+d[b[i-1]][a[i]]*c[i-1]);
            dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+
            c[i]*d[a[i-1]][b[i]]+(1-c[i])*d[a[i-1]][a[i]]);
            }
            if(j>=2)
            dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+c[i-1]*c[i]*d[b[i-1]][b[i]]
            +c[i-1]*(1-c[i])*d[b[i-1]][a[i]]+(1-c[i-1])*c[i]*d[a[i-1]][b[i]]
            +(1-c[i-1])*(1-c[i])*d[a[i-1]][a[i]]);
        }
    }
    double ans=1e9;
    for(int i=0;i<=m;i++) {
        ans=min(ans,dp[n][i][1]);
        ans=min(ans,dp[n][i][0]);
    }
    printf("%.2lf\n",ans);
}

int main()
{
    init();
    work();
    return 0;
}

 

35.双栈排序

    发现少只因素$i,
j$不克放进同一个栈当且仅当是$k$使得$i<j<k,a_k<a_i<a_j$

   
将这么i,j之间连边,整个图跑同全副二区划图染色。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
const int maxn=1005;
typedef long long LL;
using namespace std;
int n,a[maxn],col[maxn],ok[maxn],mi[maxn],fl;

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
}

void init() {
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
}

int ecnt,fir[maxn],nxt[maxn*maxn],to[maxn*maxn];
void add(int u,int v) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}

void dfs(int x) {
    for(int i=fir[x];i;i=nxt[i]) {
         if(col[to[i]]!=-1) {
            if(col[to[i]]==col[x]) fl=1; 
            return; 
         }
         else {
             col[to[i]]=col[x]^1;
             dfs(to[i]);
         }  
    }
}

stack<int>s1;
stack<int>s2;
void work() {
    memset(col,-1,sizeof(col));
    mi[n]=a[n];
    for(int i=n-1;i>=1;i--) 
        mi[i]=min(mi[i+1],a[i]); 
    for(int i=1;i<=n;i++) 
        for(int j=i+1;j<=n;j++) 
            if(a[j]>a[i]&&(j+1<=n&&mi[j+1]<a[i])) 
                add(i,j);
    for(int i=1;i<=n;i++) 
        if(col[i]==-1) { 
            col[i]=1;
            dfs(i);
            if(fl) break;
        }
    if(fl) {
        printf("0\n");
        return;
    }
    int now=0;
    for(int i=1;i<=n;i++) {
        int x=s1.empty()?0:s1.top();
        int y=s2.empty()?0:s2.top();
        while(x==now+1) {
            s1.pop();
            x=s1.empty()?0:s1.top();
            now++;
            printf("b ");
        }
        if(col[i]==1) {
            s1.push(a[i]);
            printf("a ");
        }
        else {
            while(y==now+1) {
                s2.pop();
                y=s2.empty()?0:s2.top();
                now++;
                printf("d ");
            }
            s2.push(a[i]);
            printf("c "); 
        }
    }
    while(!s1.empty()||!s2.empty()) {
        int x=s1.empty()?0:s1.top();
        int y=s2.empty()?0:s2.top();
        if(x==now+1) {
            now++;
            printf("b ");
            s1.pop();
        }
        else if(y==now+1) {
            now++;
            printf("d ");
            s2.pop();
        }
    }
    printf("\n");
}

int main() 
{
    init();
    work();
    return 0;
}

 

36.组合数问题

   
这种水题去年之自己还是做不来?太死啦,怪不得即时学长感觉甚无语23333

   
n^2预处理发生组合数和答案,O(1)询问即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
typedef long long LL;
using namespace std;
int n,m,k,t,C[2005][2005],ans[2005][2005]; 

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
}

void pre() {
    for(int i=0;i<=2000;i++) C[i][0]=1;
    for(int i=1;i<=2000;i++) {
        for(int j=1;j<=2000;j++) {
            if(j<=i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%k;
            ans[i][j]=ans[i][j-1];
            if(j<=i&&!C[i][j]) ans[i][j]++;
        }
    }
    for(int i=1;i<=2000;i++) 
        for(int j=1;j<=2000;j++)
            ans[i][j]+=ans[i-1][j];
}

void init() {
    read(t); read(k);
    pre();
    for(int i=1;i<=t;i++) {
        read(n); read(m);
        m=min(n,m);
        printf("%d\n",ans[n][m]);
    }
}

int main()
{
    init();
    return 0;
}

  

37.子串

   
dp.比较好纪念,dp[i][j][k]意味着手上配合到b的第i员,已经为此了j只错,当且号匹配或者未配合的方案往往。

   
注意,开滚动数组转移,不合法的状态而赋为0。然后上平等员是配合上之及时同一位连续配合的语可不开啊得再开平段落。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
typedef long long LL;
using namespace std;
const int maxn=1005;
const int maxm=205;
int n,m,kk;
const int mod=1e9+7;
char a[maxn],b[maxm];
LL dp[2][maxm][maxm][2];

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
}

void init() {
    read(n); read(m); read(kk);
    scanf("%s",a+1);
    scanf("%s",b+1);
}

void work() {
    int o=0;    
    LL ans=0;
    dp[o][0][0][0]=1;
    for(int i=1;i<=n;i++) {
        o^=1;
        int up=min(i,m);
        for(int j=0;j<=m;j++)
            for(int k=0;k<=j;k++) {
                dp[o][j][k][0]=(dp[o^1][j][k][0]+dp[o^1][j][k][1])%mod;
                if(a[i]==b[j]) {
                    dp[o][j][k][1]=dp[o^1][j-1][k][1];
                    if(k) (dp[o][j][k][1]+=(dp[o^1][j-1][k-1][0]+dp[o^1][j-1][k-1][1])%mod)%mod;
                }
                else dp[o][j][k][1]=0;
                if(k==kk&&j==m) (ans+=dp[o][j][k][1])%=mod;
            }
    }
    printf("%lld\n",ans);
}

int main()
{
    init();
    work();
    return 0;
}

  

38.蚯蚓

老三个序列维护。

小心要起来LL,然后起了LL以后极大值如果有那么稀。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
#define INF 1e18
typedef long long LL;
using namespace std;
const int maxm=7e6+5;
const int maxn=1e5+5;
int n,m,q,u,v,t;
LL a[maxn];
queue<LL>que[3];

void read(LL &ret) {
    char ch=getchar(); ret=0;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
}

bool cmp(const int &A,const int &B) {
    return A>B;
}

void init() {
    scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
    for(int i=1;i<=n;i++) read(a[i]);
}

LL ck(int i) {
    return que[i].empty()?-INF:que[i].front();
}

void work() {
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++) que[0].push(a[i]); 
    for(int ti=1;ti<=m;ti++) {
        LL a=ck(0),b=ck(1),c=ck(2);
        LL mx=max(max(a,b),c);
        if(mx==a) 
            que[0].pop();
        else 
            if(mx==b) que[1].pop();
        else 
            que[2].pop();
        mx+=(LL)(ti-1)*q;
        if(ti%t==0) printf("%lld ",mx);
        LL ll=((double)u/v)*mx,rr=mx-ll;
        if(ll<rr) swap(ll,rr);
        que[1].push(ll-ti*q);
        que[2].push(rr-ti*q);
    }
    printf("\n");
    int sz=0;
    for(;;) {
        LL a=ck(0),b=ck(1),c=ck(2);
        LL mx=max(max(a,b),c);
        if(mx==a) 
            que[0].pop();
        else 
            if(mx==b) que[1].pop();
        else 
            que[2].pop();
        mx+=(LL)m*q;
        ++sz;
        if(sz%t==0) printf("%lld ",mx);
        if(sz==n+m) break;
    }
    printf("\n");
}

int main()
{
    init();
    work();
    return 0;
}

 

39. 解方程

   
对质数p取模,若数i不合法则i+p也非合法。多收获几独模型一模,把非合法的筛掉。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
typedef long long LL;
using namespace std;
const int maxn=1000005;
LL n,m,a[150][5],p[5]={10007,10917,30071,12007,65537},no[maxn];

void read(LL ret[]) {
    char ch=getchar(); int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) {
        for(int i=0;i<5;i++) 
        ret[i]=(ret[i]*10+ch-'0')%p[i]; 
    }
    if(f==-1) {
        for(int i=0;i<5;i++)
            ret[i]=p[i]-ret[i];
    }
}

void init() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+1;i++) read(a[i]);
}

int ok(int x,int o) {
    LL sum=0,xx=x;
    for(int i=n+1;i>=1;i--) {
        sum=((sum+a[i][o])*xx)%p[o];
    }
    return sum==0;
}

void work() {
    for(int o=0;o<5;o++) {
        for(int i=1;i<=p[o];i++) {
            if(!ok(i,o)) {
                for(int j=i;j<=m;j+=p[o]) {
                    no[j]=1;
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=m;i++) if(!no[i])
        ans++;
    printf("%d\n",ans);
    for(int i=1;i<=m;i++) if(!no[i])
        printf("%d\n",i);
}

int main()
{
    init();
    work();
    return 0;
}

  

40.运载计划

   
 又平等志树上差分。二分割+树上差分。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
const int maxn=300005;
typedef long long LL;
using namespace std;
int n,m;

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
}

int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
void add(int u,int v,int w) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}

int x[maxn],y[maxn],z[maxn],d[maxn];
void init() {
    read(n); read(m);
    for(int i=1;i<n;i++) {
        int u,v,w;
        read(u); read(v); read(w);
        add(u,v,w);
    }
    for(int i=1;i<=m;i++) {
        read(x[i]); read(y[i]);
    }
}

int R[maxn],f[maxn][20],dis[maxn];
void dfs(int x,int fa) {
    f[x][0]=fa; R[x]=R[fa]+1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        dis[to[i]]=dis[x]+val[i];
        dfs(to[i],x);
    }
}

void make_st() {
    for(int i=1;i<=19;i++)
        for(int j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1];
}

int get_lca(int a,int b) {
    if(R[a]<R[b]) swap(a,b);
    for(int i=19;i>=0;i--) 
        if(f[a][i]&&R[f[a][i]]>=R[b])
            a=f[a][i];
    if(a==b) return a;
    for(int i=19;i>=0;i--)
        if(f[a][i]&&f[a][i]!=f[b][i])
            a=f[a][i],b=f[b][i];
    return f[a][0];
}

int g[maxn],cnt,mxx;
int DFS(int x,int fa,int pr,int mid) {
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        if(DFS(to[i],x,i,mid)) return 1;
        g[x]+=g[to[i]];
    }
    if(g[x]==cnt&&mxx-val[pr]<=mid) return 1;
    return 0;
}

int check(int mid) {
    cnt=0; mxx=0;
    memset(g,0,sizeof(g));
    for(int i=1;i<=n;i++) {
        if(d[i]>mid) {
            cnt++;
            g[x[i]]++; g[y[i]]++; g[z[i]]-=2;
            mxx=max(mxx,d[i]);
        }
    }
    return DFS(1,0,0,mid);
}

void work() {
    dfs(1,0);
    make_st();
    for(int i=1;i<=n;i++) {
        z[i]=get_lca(x[i],y[i]);
        d[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]];
    }
    int l=0,r=3e8,ans;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1; 
    }
    printf("%d\n",ans);
}

int main()
{
    init();
    work();
    return 0;
}

 

41.开车旅行

   
把高度排序连成链表,从1交n看每个人左右季独,它的尽充分与潮不行定在中间,然后将她自从链表中删掉保证现在设摸的食指左右还以它们背后。

   
然后同轮子开车吧a跳到她的次大b再跳到其的无比要命,做倍增。

   
感觉那个好写的下一场发了同样可怜堆智障错误,调至已故。。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
#define INF 0xfffffff
const int maxn=100005;
typedef long long LL;
using namespace std;
int n,m,h[maxn],a[maxn],zd[maxn],cd[maxn],x0,s[maxn],lim[maxn];

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0'; ret*=f;
}

bool cmp(const int &A,const int &B) {
    return h[A]<h[B];
}

void init() {
    read(n);
    for(int i=1;i<=n;i++) {
        a[i]=i; read(h[i]);
    }
    read(x0); read(m);
    for(int i=1;i<=m;i++) {
        read(s[i]); read(lim[i]);
    }
}

int p[maxn][20];
LL da[maxn][20],db[maxn][20];
void make_st() {
    for(int i=1;i<=n;i++) {
        p[i][0]=zd[cd[i]];
        da[i][0]=abs(h[cd[i]]-h[i]);
        db[i][0]=abs(h[zd[cd[i]]]-h[cd[i]]);
    }
    for(int i=1;i<=19;i++)
        for(int j=1;j<=n;j++) {
            p[j][i]=p[p[j][i-1]][i-1];
            da[j][i]=da[j][i-1]+da[p[j][i-1]][i-1];
            db[j][i]=db[j][i-1]+db[p[j][i-1]][i-1];
        }
}

void cal(int st,int limit,LL &az,LL &bz) {
    int now=st;
    az=0; bz=0;
    for(int i=19;i>=0;i--) {
        if(p[now][i]&&az+bz+da[now][i]+db[now][i]<=limit) {
            az+=da[now][i];
            bz+=db[now][i];
            now=p[now][i];
        }
    }
    if(cd[now]&&az+bz+abs(h[cd[now]]-h[now])<=limit) 
        az+=abs(h[cd[now]]-h[now]);
}

void ck(int i,int x,int &a,int &b) {
    if(!i) return;
    if(!a) a=i;
    else if(!b) {
        b=i;
        if(abs(h[a]-h[x])>abs(h[b]-h[x])) swap(a,b);
    }
    else {
        if(abs(h[i]-h[x])<abs(h[a]-h[x])) 
            b=a,a=i;
        else if(abs(h[i]-h[x])<abs(h[b]-h[x]))
            b=i;
    }
}

int pr[maxn],nx[maxn];
void work() {
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++) {
        pr[a[i]]=a[i-1];
        nx[a[i]]=a[i+1];
    }
    for(int i=1;i<=n;i++) {
        int aa=0,bb=0;
        ck(pr[i],i,aa,bb);
        ck(pr[pr[i]],i,aa,bb);
        ck(nx[i],i,aa,bb);
        ck(nx[nx[i]],i,aa,bb);
        if(nx[i]) pr[nx[i]]=pr[i];
        if(pr[i]) nx[pr[i]]=nx[i];
        zd[i]=aa; cd[i]=bb;
    }
    make_st();
    int ans=0,ok=0;
    double now=INF;
    for(int i=1;i<=n;i++) {
        LL a,b;
        cal(i,x0,a,b);
        if(!ok||(double)a/b<now) {
            ans=i; ok=1;
            now=(double)a/b;
        }
    }
    printf("%d\n",ans);
    for(int i=1;i<=m;i++) {
        LL a,b;
        cal(s[i],lim[i],a,b);
        printf("%lld %lld\n",a,b);
    }
}

int main()
{
    init();
    work();
    return 0;
}

 

42.愤怒的鸟儿

   
其实去年考了Noip不久纵写了即道题,不过这看还是老大为难,而且几乎以在某个题解抄了千篇一律通后来祥和有史以来没有印象,就以写了瞬间。

   
然后发现实际特别简单的,而且感觉去年d2比d1简短得多呀,

   
d1t1休说了签证到开,t2,一道史无前例的神题,t3又考了盼望,难得一样比,相比d2t1水题,t2暴力时有发生70~85分,t3趟状压,多么亲切。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
#define eps 1e-10
typedef long long LL;
using namespace std;
const int maxn=20;
int n,m,tot,z[500],dp[1<<19];
double x[maxn],y[maxn];

void cal(int u,int v) {
    if(x[u]==x[v]) return ;
    double b=(y[u]*x[v]*x[v]-y[v]*x[u]*x[u])/(x[u]*x[v]*x[v]-x[v]*x[u]*x[u]);
    double a=(y[u]-b*x[u])/(x[u]*x[u]);
    if(a>0) return ;
    z[++tot]|=(1<<u-1);
    z[tot]|=(1<<v-1);
    for(int k=v+1;k<=n;k++) 
        if(fabs(x[k]*x[k]*a+x[k]*b-y[k])<=eps)
            z[tot]|=(1<<k-1);
}

void work() {
    tot=0;
    memset(dp,127,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++) 
    for(int j=i+1;j<=n;j++) 
    cal(i,j);
    for(int i=1;i<=n;i++) z[++tot]=(1<<i-1);
    int nn=(1<<n)-1;
    for(int j=0;j<=nn;j++) 
        for(int i=1;i<=tot;i++)
            if((j|z[i])>j) 
                 dp[j|z[i]]=min(dp[j|z[i]],dp[j]+1);
    printf("%d\n",dp[nn]);
    for(int i=1;i<=tot;i++) z[i]=0;
}

void init() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%lf%lf",&x[i],&y[i]);
        work();
    }
}

int main()
{
    init();
    return 0;
}

  

 43.疫情控制

   
二私分+树上贪心。下次是匪是拖欠发同志次分开+树上dp了。

   
De了超级久的Bug,然后今天洛谷还各种炸。。。

   
不得不说codevs真是,,直到洛谷活过来给自家A了都没有测量出来

    题解:

       
贪心:若一个师没有到根,那么它进一步往上运动越精彩。

       
二分一个答案,每个军队倍增地往上超,若是在答案范围外超过不顶根本,就把能过到的最高点占领。

       
若是能超过到清还会超过,就怀下来,方便他人用。

       
dfs一所有将已下的子树确定下来,然后处理没有叫全然占领的子树。这些地方必定是当与的儿那里被占领。

       
贪心:询问没有给统统占领的幼子,若是它这里发生一个还能够超越的距离小于它到清的就是一直由它们来占领好,可以就此个堆放维护。(记得清0)

       
(自己之不自然帮自己,存在好的儿子遭遇之武装部队去扶别人再次让其他一个丁来提携自己之图景)

       
剩下的幼子交清的离开存下来,排序,和还能够超越的数组排序,贪心地起最可怜之开头于。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
typedef long long LL;
using namespace std;
const int maxn=50005;

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0'; ret*=f;
}

int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
void add(int u,int v,int w) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}

LL sum;
int n,m,is[maxn],sz;
void init() {
    read(n);
    for(int i=1;i<n;i++) {
        int u,v,w;
        read(u); read(v); read(w);
        add(u,v,w);
        sum+=w;
    }
    read(m);
    for(int i=1;i<=m;i++) {
        int x;
        read(x);
        is[++sz]=x;
    }
}

int f[maxn][20];
LL d[maxn][20];
void dfs(int x,int fa) {
    f[x][0]=fa;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        d[to[i]][0]=val[i];
        dfs(to[i],x);
    }
}

void make_st() {
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++) {
             f[i][j]=f[f[i][j-1]][j-1];
             d[i][j]=d[i][j-1]+d[f[i][j-1]][j-1];
        }
}

int ok[maxn];
int DFS(int x,int fa) {
    int fl=1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        if(ok[to[i]]) continue;
        if(!DFS(to[i],x)) fl=0;
        else ok[to[i]]=1;
    }
    if(fl==0||!nxt[fir[x]]) return 0;
    return 1;
}

bool cmp(const int &A,const int &B) {
    return A>B;
}

priority_queue<int,vector<int>,greater<int> >que[maxn];
int a[maxn],b[maxn],tota,totb;
int check(LL mid) {
    if(mid==1) {
        int debug=1;
    }
    memset(ok,0,sizeof(ok));
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    tota=totb=0;
    for(int i=fir[1];i;i=nxt[i]) {
        int y=to[i];
        while(!que[y].empty() ) {
            que[y].pop();
        }
    }
    for(int i=1;i<=sz;i++) {
        int x=is[i];
        if(x==1) a[++tota]=mid;
        LL now=0;
        for(int j=19;j>=0;j--) 
            if(f[x][j]&&f[x][j]!=1&&d[x][j]+now<=mid) {
                now+=d[x][j];
                x=f[x][j];
            }
        if(f[x][0]==1&&now+d[x][0]<mid) {
            que[x].push(mid-(now+d[x][0]));
        }
        else ok[x]=1;
    }
    if(ok[1]) return 1;
    if(DFS(1,0)) return 1;
    for(int i=fir[1];i;i=nxt[i]) {
        int y=to[i];
        if(!ok[y]) {
            if(!que[y].empty() ) {
                int z=que[y].top();
                if(z<val[i]) {
                    que[y].pop();
                    ok[y]=1;
                }
                else b[++totb]=val[i];
            }
            else b[++totb]=val[i];
        }
        while(!que[y].empty()) {
             int z=que[y].top();
             a[++tota]=z;
             que[y].pop();
        }
    }
    if(!totb) return 1;
    sort(a+1,a+tota+1,cmp);
    sort(b+1,b+totb+1,cmp);
    for(int i=1;i<=totb;i++) 
        if(a[i]<b[i]) return 0;
    return 1;
}

void work() {
    dfs(1,0);
    make_st();
    LL l=0,r=sum,ans=-1;
    while(l<=r) {
        LL mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld\n",ans);
}

int main()
{
    init();
    work();
    return 0;
}

 

44.飞扬的禽

debug到怀疑人生系列

背包,往下丢是01背包,往上动是一点一滴背包。

差一点个坑点,dp[i-1][m]可变至dp[i][m](到了至继续朝上或当顶上)

进化飞转移的下偏偏判定从i-1转移来之状态而合法,i转移来的状态不自然合法(连续超过多次实在是一次性超过上的,中途之有位置不自然合法)

优先走为上跨的又跑为生掉的(不可知由少来的职务往上过)。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cmath>
#include<ctime>
#define INF 0xfffffff
typedef long long LL;
using namespace std;
const int maxn=10005;
int n,m,kk;
int up[maxn],dn[maxn],l[maxn],h[maxn];

void read(int &ret) {
    char ch=getchar(); ret=0;int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0'; ret*=f;
}

void init() {
    read(n); read(m); read(kk);
    for(int i=1;i<=n;i++) {
        read(up[i]);
        read(dn[i]);
        l[i]=0; h[i]=m+1;
    }
    l[0]=0; h[0]=m+1;
    for(int i=1;i<=kk;i++) {
        int x,ll,r;
        read(x); 
        read(ll);
        read(r);
        l[x]=ll; h[x]=r;
    }
}

int ok(int i,int j) {
    return j>l[i]&&j<h[i];
}

int dp[maxn][1005],now;
void work() {
    for(int i=1;i<maxn;i++)
        for(int j=1;j<=1000;j++)
            dp[i][j]=INF;
    for(int i=1;i<=m;i++) dp[0][i]=0; 
    int fl=1,as,ans=1e9;
    for(int i=1;i<=n;i++) {
        fl=0;
        for(int j=1;j<=m;j++) {
            if(j>up[i]) {
                if(ok(i-1,j-up[i]))
                    dp[i][j]=min(dp[i][j],dp[i-1][j-up[i]]+1);
                dp[i][j]=min(dp[i][j],dp[i][j-up[i]]+1);
            }
            if(j==m) {
                for(int k=up[i];k>=0;k--) {
                    if(ok(i-1,j-k))
                    dp[i][j]=min(dp[i][j],dp[i-1][j-k]+1);
                    dp[i][j]=min(dp[i][j],dp[i][j-k]+1);
                }
            }
        } 
        for(int j=l[i]+1;j<=h[i]-1;j++) {
            if(j+dn[i]<=m&&ok(i,j)&&ok(i-1,j+dn[i])) {
                dp[i][j]=min(dp[i][j],dp[i-1][j+dn[i]]);
            }
            if(i==n) ans=min(ans,dp[i][j]);
            if(dp[i][j]!=INF) fl=1;
        }
        if(!fl) break;
        if(l[i]!=0||h[i]!=m+1) now++;
    }
    if(!fl) printf("0\n%d\n",now);
    else {
        printf("1\n");
        printf("%d\n",ans);
    }
}

int main()
{

    init();
    work();
    return 0;
}

 

45.积木大赛

   
差分,相当给在每个位置加要减多少,一个加得和一个减配对,于是将大于0的组成部分与小于0的组成部分各自绝对值加起来取max就是答案。

//Twenty
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
const int maxn=100005;
using namespace std;
typedef long long LL;
int n,a[maxn],b[maxn],aa,bb;

void read(int &x) {
    int ret=0,f=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    x=ret*f;
}

void init() {
    read(n);
    for(int i=1;i<=n;i++) {
        read(a[i]);
        b[i]=a[i]-a[i-1];
        if(b[i]>0) aa+=b[i];
        else bb-=b[i];
    }
    aa=max(aa,bb);
    printf("%d\n",aa);
}

int main()
{
    init();
    return 0;
}

 

46.树网的对

新一拘禁那个不便,然而数据范围表示是平等鸣水题。

对此每个点进行相同坏dfs求出她到外接触之偏离,这个以请出树的直径(从某点dfs到最远点,该点再dfs到绝远点);

下一场直径暴力跑就只是过。何况数据和得千篇一律比。

 

//Twenty
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
typedef long long LL;
using namespace std;
const int maxn=305;
int n,s,x,y,z,d[maxn][maxn],que[maxn],ql=1,qr;

void read(int &x) {
    x=0; int f=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],f[maxn];
void add(int u,int v,int w) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}

void init() {
    read(n); read(s);
    for(int i=1;i<n;i++) {
        read(x); read(y); read(z);
        add(x,y,z);
    }
}

void dfs(int x,int fa,int top,int o) {
     if(o) f[x]=fa;
     for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
         d[to[i]][top]=d[x][top]+val[i];
         d[top][to[i]]=d[to[i]][top];
         dfs(to[i],x,top,o);
     }
}

int ans=1e9;
void ck(int a,int b) {
    int as=0;
    for(int i=1;i<=n;i++) {
        int cc=min(d[a][i],d[b][i]);
        for(int j=ql;j<=qr;j++)
            cc=min(cc,d[que[j]][i]);
        as=max(as,cc);
    }
    ans=min(ans,as);
}

void cal(int xx,int yy,int lim) {
    int s=yy,t=xx,l=s,r=s,now=0;
    while(r!=t&&now+d[r][f[r]]<=lim) {
        now+=d[r][f[r]];
        if(r!=s) que[++qr]=r;
        r=f[r];
    }
    ck(l,r);
    while(r!=t) {
        now-=d[l][f[l]]; l=f[l];
        ql++; int pr=r;
        while(r!=t&&now+d[r][f[r]]<=lim) {
            now+=d[r][f[r]];
            if(r!=pr) que[++qr]=r;
            r=f[r];
        }
        ck(l,r);
    }
    printf("%d\n",ans);
}

void work() {
    int xx=0,yy=0;
    for(int i=1;i<=n;i++) {
        if(i==xx) {
            dfs(i,0,i,1);
            for(int j=1;j<=n;j++) {
                 if(!yy||d[i][j]>d[i][yy])
                     yy=j;
             }
        }
        else dfs(i,0,i,0);
        if(i==1) {
             for(int j=2;j<=n;j++) {
                 if(!xx||d[i][j]>d[i][xx])
                     xx=j;
             }
        }
    }
    cal(xx,yy,s);   
}

int main()
{
    init();
    work();
    return 0;
}

 

 


原本计划上周四底典范将结束之跟着洛谷刷noip题被自己拖到了现在。。去丢纯粹的入门难度水题大概就是35志的法,然而我形容得并无算是多顺利,足见自己有弱QAQ

对noip题多少来得觉得了吧,虽然听说今年见面转移难。

还有17天便noip了,一年带点的斗生涯大概会就此结束了,毕竟比打创造奇迹的食指,世界上还是尚未能创奇迹的总人口大多得几近嘛(虽然我相信水团会创好之偶尔)。

前面在知乎上视一个答,小时候踌躇满志少女战士充分生气,小朋友们同打闹角色扮演的上,特别羡慕那些选择粉色的女孩子,大家都是第一坏出生在这个世界上,怎么就有胆略选最好的呢。

实质上自己好的语句以前为充分为难完成,后来坏尽力地思念尝试一尝试,后来历次都黄了呀。

自身从小到异常无比爱的少数桩业务还是呀,

累败累战,累战累败吧。

不亮堂自己当游说几什么。

兹手机欠费了,不可知时时去押比赛退役是哪些的体验了。