0905フィルムあなたのレースのテスト

羅区P3942一般のコマンド

タイトル説明

私は4月と考えます。
地域が選択されていない場合、それはおそらく、そう簡単に右、別れのではないでしょうか?別の元チームメイトは部屋を出た後、私は1つを見ました。
6月のMoとのモンキーは、その後、物事は地面から百万骨髄を取得します。
ドリーム、一般的な秘密の手紙に宅配便で小さなFになりました。
今、そこにフロントラインの将軍に国民の生命と死の必要性に関連する2通の秘密の手紙であり、時間が不足して大規模な、危険な道路を占めました。Fは、その大金ではなく、トレンド、このタスクを引き受ける勇気を避けます。
しかし、それはFが不注意小さい、彼は誤ってオフにノックする秘密の手紙の中で2を入れました。
Fは密かに小さな残りその封書を開きました。彼は非常に詳細な地図のほか、いくつかの承認を見つけた-それは、マップの周りの戦場インテリジェンスました。1パスでバー1の長さは、各パス2双方向接続異なるポストであり、ポストは間とすることができる-が、彼はよく見た後、n個のマップ上のマークは、1からnにイン番号を、nはことがわかりましたトレイル二十から二でアクセス可能。
小さなFは慎重に上記のコメントを識別し、突然、私は行方不明の手紙の内容を理解していました。もともとは、各ポストがチームを駐留することができ、距離を制御することができ、各チームは、旅館でのkを超えていません。制御すべきポストがない場合、危険な生成することは容易である-ので、このような状況を完全に避けるべきです。そして、それは失われた秘密の手紙を封印し、それが絶妙な配置スキーム大臣で満たされている最小インのすべてのチームを制御するために使用された裁判所の数学を、左。
Fは、私たちが最適解を計算することができれば、おそらく彼は罪悪感、死からの自由を作業することができます、少し知っています。彼はあなたを見つけた、あなたは彼を助けることができますか?もちろん、プロセス内のご支援を待っている小さなFは、いくつかのチャートから、より有用な性質であり得ることを観察したかもしれない、彼はあなたを伝えるために特別な方法を渡します。

入力形式

標準入力データから読み込みます。
最初の入力ライン1の最も遠隔正の整数であり、N、K、Tの特殊な性質で表される数は、ポストの数を表し、チームを制御することができます。範囲の特殊性に関するデータを参照します。
2つの正の整数UI、VI、UIおよびVIのn行への入力ライン2が表す
軌跡の長さがある部屋、。
出力フォーマット
を標準出力に出力します。
出力ライン、必要に応じて次の最適解のためのチームの数。

サンプル入力出力
入力1
4 1 0
1 2
。1. 3
。1. 4
出力1
。1  
入力1
6 1 0
1 2
。1. 3
。1. 4
。4. 5
。4. 6
出力2
2

解決

  各極小点の貪欲、深さは、それが選択されている場合、値の特定の範囲と最大の効果を置く必要があり、この時点で、チームに配置されるk番目の時点まで行かない場合は、参照するように制御されます。

  次に、どのように反応性の点を検討します。チームのために、チームは、その後距離を確実に制御することがU点KAに等しい未満であり、Uは(<k)の点を距離う。

  その後、我々は、ポイント値に重みを付ける、それは半径距離があろう点に制御される表します。

  私たちは一点でチームを置くときは、右の点の値がkに割り当てられ、その父の重みがK-1に割り当てられ、彼の父の父の重みはK-2に割り当てられます。

  我々が制御される点のような点からの距離に等しい量の存在下、この時点よりも大きいため、Kをルックアップ父であるか否かを判断した場合

  コードは以下の通りです

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
int n,k,t,ans,cnt;
int v[maxn*2],nx[maxn*2],info[maxn];
int q[maxn],fa[maxn],dep[maxn],vis[maxn];
bool cmp(int a,int b){return dep[a]>dep[b];}
void add(int u1,int v1){nx[++cnt]=info[u1];info[u1]=cnt;v[cnt]=v1;}
void dfs(int x,int f){dep[x]=dep[fa[x]=f]+1;for(int i=info[x];i;i=nx[i])if(v[i]!=f)dfs(v[i],x);}
int main()
{
    scanf("%d%d%d",&n,&k,&t);q[n]=n;vis[n]=-1;
    for(int i=1,u1,v1;i<n;i++)scanf("%d%d",&u1,&v1),add(u1,v1),add(v1,u1),q[i]=i,vis[i]=-1;
    dfs(1,0);sort(q+1,q+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        int flag=(vis[q[i]]>=0),an=q[i];
        for(int j=1;j<=k&&fa[an];j++)an=fa[an],flag|=(vis[an]>=j);
        if(flag)continue;vis[an]=k;ans++;
        for(int j=1;j<=k&&fa[an];j++)an=fa[an],vis[an]=max(vis[an],k-j);
    }
    printf("%d\n",ans);
}

洛谷P3941 入阵曲

题目描述

小 F 很喜欢数学,但是到了高中以后数学总是考不好。
有一天,他在数学课上发起了呆;他想起了过去的一年。一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然一新。这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以 解决的问题,被一个又一个算法轻松解决。
小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢。
一年过去了,想想都还有点恍惚。
他至今还能记得,某天晚上听着入阵曲,激动地睡不着觉,写题写到鸡鸣时分都兴奋不 已。也许,这就是热血吧。

也就是在那个时候,小 F 学会了矩阵乘法。让两个矩阵乘几次就能算出斐波那契数列的 第 10^100项,真是奇妙无比呢。
不过,小 F 现在可不想手算矩阵乘法——他觉得好麻烦。取而代之的,是一个简单的小 问题。他写写画画,画出了一个
n×m的矩阵,每个格子里都有一个不超过 k的正整数。
小 F 想问问你,这个矩阵里有多少个不同的子矩形中的数字之和是k 的倍数? 如果把一个子矩形用它的左上角和右下角描述为
(x1,y1,x2,y2),其中x1≤x2,y1≤y2; 那么,我们认为两个子矩形是不同的,当且仅当他们以
(x1,y1,x2,y2)表示时不同;也就是 说,只要两个矩形以
(x1,y1,x2,y2)表示时相同,就认为这两个矩形是同一个矩形,你应该 在你的答案里只算一次。

输入格式
从标准输入中读入数据。
输入第一行,包含三个正整数 n,m,k。
输入接下来 n 行,每行包含m个正整数,第i行第j列表示矩阵中第i行第j列中所填的正整数 aij
输出格式
输出到标准输出中。
输入一行一个非负整数,表示你的答案。
输入输出样例
输入 #1
2 3 2
1 2 1
2 1 2
输出 #1
6

解析

  很容易想到枚举左上右下两个端点,但这样肯定超时。

  于是试着想了一下中途相遇法,枚举左上右上两个端点然后储存它们的信息,之后枚举左下右下两个端点时直接处理就好。

  然后。。。。。。发现可以枚举矩阵的左边界与右边界,然后将中间每一行的值加起来缩成一个点。然后再求一个前缀和,模k相同余数的就可以组合到一起,对于每个余数,贡献就是 个数*(个数-1)/2,另外注意余数为0的情况

  代码

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
int n,k,t,ans,cnt;
int v[maxn*2],nx[maxn*2],info[maxn];
int q[maxn],fa[maxn],dep[maxn],vis[maxn];
bool cmp(int a,int b){return dep[a]>dep[b];}
void add(int u1,int v1){nx[++cnt]=info[u1];info[u1]=cnt;v[cnt]=v1;}
void dfs(int x,int f){dep[x]=dep[fa[x]=f]+1;for(int i=info[x];i;i=nx[i])if(v[i]!=f)dfs(v[i],x);}
int main()
{
    scanf("%d%d%d",&n,&k,&t);q[n]=n;vis[n]=-1;
    for(int i=1,u1,v1;i<n;i++)scanf("%d%d",&u1,&v1),add(u1,v1),add(v1,u1),q[i]=i,vis[i]=-1;
    dfs(1,0);sort(q+1,q+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        int flag=(vis[q[i]]>=0),an=q[i];
        for(int j=1;j<=k&&fa[an];j++)an=fa[an],flag|=(vis[an]>=j);
        if(flag)continue;vis[an]=k;ans++;
        for(int j=1;j<=k&&fa[an];j++)an=fa[an],vis[an]=max(vis[an],k-j);
    }
    printf("%d\n",ans);
}

 

洛谷P3943 星空

题目描述
逃不掉的那一天还是来了,小 F 看着夜空发呆。
天上空荡荡的,没有一颗星星——大概是因为天上吹不散的乌云吧。
心里吹不散的乌云,就让它在那里吧,反正也没有机会去改变什么了。
小 C 拿来了一长串星型小灯泡,假装是星星,递给小 F,想让小 F 开心一点。不过,有 着强迫症的小 F 发现,这串一共 n 个灯泡的灯泡串上有 k 个灯泡没有被点亮。小 F 决定 和小 C 一起把这个灯泡串全部点亮。
不过,也许是因为过于笨拙,小 F 只能将其中连续一段的灯泡状态给翻转——点亮暗灯 泡,熄灭亮灯泡。经过摸索,小 F 发现他一共能够翻转 m 种长度的灯泡段中灯泡的状态。
小 C 和小 F 最终花了很长很长很长很长很长很长的时间把所有灯泡给全部点亮了。他 们想知道他们是不是蠢了,因此他们找到了你,让你帮忙算算:在最优的情况下,至少需要 几次操作才能把整个灯泡串给点亮?
输入格式
从标准输入中读入数据。
输入第 1 行三个正整数 n,k,m。
输入第 2 行k个正整数,第i个数表示第 i 个被没点亮的灯泡的位置 ai。
输入第 3 行m个正整数,第i个数表示第 i 种操作的长度bi。
保证所有bi互不相同;保证对于
1≤i<k1有ai<ai+1;保证输入数据有解。
输出格式
输出标准输入中。
输出一行一个非负整数,表示最少操作次数。
输入输出样例
输入 #1
5 2 2
1 5
3 4
输出 #1
2  

解析

  区间反转实现起来有一些困难,所以考虑转换。

  发现只要把原来的01状态数组转化成前缀亦或和数组,就可以再O(1)的时间复杂度内实现翻转,

  比如反转原数组的l到l+r,就相当于原数组l到l+r-1都要亦或1

  新数组中只需要l和r+1亦或1就可以了即每次翻转可转化为亦或l与l+len。

  若l,l+len都为1,则减少两个1

  若其中一个为1,则相当于交换1的位置。

  现在要把所有1都消掉,是不是有点像图论?。

  因为k很小,所以可以先用bfs求出任意两个1消掉的最小代价,然后直接状压dp

  代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;queue<int>q;
int n,m,cnt,I,K,d[40005],f[2000000],bit[40005],len[65],pos[25],w[25][25];
void bfs(int x)
{
    memset(d,0x3f,sizeof d);q.push(pos[x]);d[pos[x]]=0;
    while(!q.empty())
    {
        int nw=q.front();q.pop();
        for(int i=1;i<=m;i++)
        {
            if(nw+len[i]<=n+1&&d[nw+len[i]]==inf)d[nw+len[i]]=d[nw]+1,q.push(nw+len[i]);
            if(nw-len[i]>=1&&d[nw-len[i]]==inf)d[nw-len[i]]=d[nw]+1,q.push(nw-len[i]);
        }
    }
    for(int i=1;i<=cnt;i++)if(d[pos[i]]!=inf)w[x][i]=d[pos[i]];
}
int main()
{
    scanf("%d%d%d",&n,&K,&m);
    for(int i=1,x;i<=K;i++)scanf("%d",&x),bit[x]^=1,bit[x+1]^=1;
    for(int i=1;i<=m;i++)scanf("%d",&len[i]);
    for(int i=1;i<=n+1;i++)if(bit[i])pos[++cnt]=i;
    memset(w,0x3f,sizeof w);memset(f,0x3f,sizeof f);
    for(int i=1;i<=cnt;i++)bfs(i);
    f[0]=0;I=(1<<cnt)-1;
    for(int s=1;s<=I;s++)
        for(int i=0;(1<<i)<=s;i++)
            for(int j=i+1;(1<<j)<=s&&(s&(1<<i));j++)
            {
                if(!(s&(1<<j)))continue;
                f[s]=min(f[s],f[(s^(1<<i))^(1<<j)]+w[i+1][j+1]);
            }
    printf("%d\n",f[I]);
}

 

おすすめ

転載: www.cnblogs.com/firecrazy/p/11494904.html