COCI 2010年3月6日T5「PROGRAM」問題への解決策
元のタイトルのうち試験は、テストで独善的暴力の優雅な練習だけでなく、結果を記述する際に、学校である羅区質問番号P5190は、効率も高いです。その後、慎重にその理由を考えて、確かに自分自身を書くために肯定的な解決策です。。。
先上题面
MIRKOは、プログラムを実行し、プログラムを書いて、次のように。最初のサイズNのアレイを開き、ゼロを割り当てます。次は彼のプログラムを実行します。次のような手順は以下のとおりです。
Cコード:
無効何か(int型のジャンプ){
int型私= 0;
一方、(iがNを<){
配列[I] =配列[I] + 1。
私=私はジャンプを+。
}
}
パスカルコード:
手続き何か(ジャンプ:倍長整数);
VAR I:倍長整数;
ベギン
I:= 0;
私がやるN <ながら、
ベギン
配列[I]:=配列[I] + 1。
私:私はジャンプを+ =;
終わり;
終わり;
あなたは、コードを実行するたびに、彼はJUMPの値を渡します。Kの合計実行時間。JUMPの着信シーケンスはX1 X2とX3の...のXkとして表すことができます。その後、彼は自分の手順をテストするように頼まが正常に機能しているQに渡されます。次のフォーマットを確認する:L、Rは、この問い合わせの順次出力値Qである、あなたのプログラムを完了するために、(L、R)を含み、RとLのアレイの出力を表しています。
入力:
2つの正の整数の最初のラインN(10 ^ 6≤1≤N)は、コード番号の表現を実行し、配列の大きさを表し、K(^ 6 1≤K≤10)。
X1X2X3 ...のXk、(1≤Xiの<N):Kの整数の第2行は、受信パラメータ値ことを意味します。
次の行の整数、Q(1つの≤Q≤10 ^ 6)は、問い合わせの数を表します。
次のクエリーQは、境界ラインLiはRI(0≤Li≤Riを<N)を表します。
出力:
数のQ合計行、および対応示します。
例:
入力:
10 4
1 1 2 1
3
0 9
2 6
7 7
出力:
35
18
3
入力:
11 3
3 7 10
3
0 10
2 6
7 7
出力:
8
2
1
入力:
1000000 6
12 3 21 436 2 19
2
12 16124
692 29021
出力:
16422
28874
サンプル説明:
試料1受信パラメータが1、1、2、1です。
アレイを実行した後、{4、3、4、3、4、3、4、3、4、3} 2 = 18 4 + 4 + 3 + 3 + 6および4です。
アレイの試料2です。{3、0、0、1、0、0、1、1、0、1、1}。
質問の分析は、アイデアを得るために直面します
まず第一に、この素晴らしいタイトルは私たちに機能を与え、機能はそれをしているのですか?
最初の添字Iに従うように、iは初期値0、各連結ジャンプであり、それははっきり。1 =私はジャンプ、2ジャンプ、ジャンプ。3 * ... N- ジャンプ(N-ジャンプ<Nを与えられました)
それが配列の配列添字1を増加させるための手段(ハロ周りに読者を防止するためであるI、自己句読点)がNの複数のジャンプの要素の値よりも小さいです
複数のサンプルの分析は、反復の同じ数、N内の同じ符号が一定で、それは二重カウント時間にドラッグがあるだろうと言うことである場合であってもよいです。同じ番号は、その数を加えた(私はAを区切るためのイニシアチブを取るために来ている)繰り返しの数次のいくつかの要素のために、ターゲット内のseq N列に統一された治療、その数のちょうど同じ倍数であることができます、一つ一つを計算し、同じ効果を得ることができます。(計算n回、n回のほかに、それらの要素、n回として+1はなぜですか?ダイレクトプラスnを行いません)そして、操作されたデジタル記録のVIS配列、ダブルカウントを避けるためにを開く(最初の操作)繰り返しの数はバックの直接無視すべての操作と同等であった番号は、各データ要素がより少ない又は10 ^ 6に等しくなることを保証するために、この方式は実現可能であることを意味します。
範囲が依頼しているので、私は最初の接頭辞やメンテナンスの配列は、あなたが、まあ、時間を節約、nの一つだけにクエリを作成しますと思いました。
+標準プロセス詳細なメモ
私は私のコメントは本当に非常に良心を書かれていると思います。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//我自己都觉得这个typedef写的很蠢,下面就用过一次longlong,懒得改了
int n,k,q;
int seq[1000005];
ll qzh[1000005];//等价于long long qzh[1000005];
short vis[1000005];//毕竟只有0和1,省点空间。。
int jump[1000005];
int cnt[1000005];
inline int read()//快读,感兴趣的可以记一下,但是确实没几个题会卡你快读
{
char ch=getchar();
int l=0;
while(ch<'0'||ch>'9'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
l=l*10+ch-'0';
ch=getchar();
}
return l;
}
inline bool comp(int a,int b)//sort的comp函数
{
return a<b;
}
int main()
{
//scanf("%d%d",&n,&k);
n=read(),k=read();//这一句等价于上面那一句,下面的所有带有read函数的都是这样
for(int i=1;i<=k;i++)
{
//scanf("%d",&jump);
jump[i]=read();
cnt[jump[i]]++;//这个就是我提到的记录每一个数字出现了多少次的数组
/* */
}
for(int i=1;i<=k;i++){
if(vis[jump[i]]==0){//VIS数组就是我提到的记录哪些数字已经被操作过,避免重复计算的数组
for(int j=1;j<=n/jump[i];j++){
seq[jump[i]*j]+=cnt[jump[i]];//计算了n次,那些元素就加了n次,做n次+1为何不直接做一次加n
}
vis[jump[i]]=1;//这个数字已经被计算过了,打上标记
}
}
seq[0]=k,qzh[0]=k;//题目小坑,无论是什么数,seq[0]都会被加一次
for(int i=1;i<=n;i++){//前缀和数组构造
qzh[i]=qzh[i-1]+seq[i];
}
// scanf("%d",&q);
q=read();
/* for(int i=0;i<=n;i++){
printf("%d ",seq[i]);
}*/
for(int i=1;i<=q;i++){
int l,r;
// scanf("%d%d",&l,&r);
l=read(),r=read();
if(l==0){
printf("%lld\n",qzh[r]);
continue;
}
printf("%lld\n",qzh[r]-qzh[l-1]);//注意是l-1千万不要写成l了!
}
}
なぜTLEありません
私はまた、このようなものが少なくない数回のn ^ 2まあで、非常に先頭をと思いますか?生きることができますか?
その理由は、財産の除数の数
O(N + N \ 2 + N \ 3 + ... + N \ N)= O(NLog N)
だから、これは自然の中でNlogNレベルであり、精神はTLE(AOAO嘆き~~~~)を横に振っています
最後に書かれました
あなたはまだここに見ることができますありがとうございました!
最近の試験は、比較的より魅力的になります説明を記述する可能性が高くなります。。
ピットを掘りました。。おそらくアップするつもりはありません。。