問題の説明
UniversalDictionaryの巧妙なビーバーはかつて私たちを驚かせました。彼は「ビーバーの計算機1.0」と名付けた新しい計算機を開発しました。それは非常に特別であり、さまざまな科学的問題で使用される予定です。
それをテストするために、スマートビーバーは1からnまでの番号のn人の科学者を招待しました。i番目の科学者がもたらしたK I、計算問題をこの電卓に 。i番目の科学者が提起した問題には1からnまでの番号が付けられ、各問題の計算は前の問題の計算結果に依存する必要があるため、番号に従って1つずつ計算する必要があります。
各質問は多数の各教授さ A 、I、 J 、I(1≤i≤n)は、Jは(1≤j≤科学者の数記述することである kはiが )質問の数であり、 I、 Jを 表します。この問題を解決するために必要なリソースユニットの数。 この計算機は非常に素晴らしいです。それは問題を一つずつ解決します。1つの問題が解決された後、次の問題が計算される前に、計算機はリソースを割り当てたり解放したりします。 計算機で最もコストのかかる操作はリソースを解放することであり、解放は割り当てよりもはるかに低速です。したがって、計算機にとって、次の各質問には前の質問以上のものが必要であることが非常に重要です。 これらの科学者からの質問に関連する情報を提供してください。これらの質問は、「悪いペア」ができるだけ少なくなるように順番に並べる必要があります。 いわゆる「不良ペア」とは、隣接する2つの問題において、後者の問題が前の問題よりも必要なリソースが少ないことを意味します。同じ科学者によって与えられた問題については、それらを計算する相対的な順序を修正する必要があることを忘れないでください。
入力フォーマット
最初の行には、科学者の数を表す整数nが含まれています。次のn行の各5つの整数であり、kはIを、 I 1、 xはiが、 Y iは、 mはiが (0≤ I、1 < M I ≤109、1≤ X I、 Y I ≤109) 、i番目の科学者の質問の数、最初の質問に必要なリソースユニットの数、およびa i、 jの計算に使用される3つの パラメーターをそれぞれ表し ます。A 、I、 J =(I、 J -1 * X I + Y I)MOD M I。
出力フォーマット
最初の行は整数を出力し、最適な順序で「不良ペア」の最小数を示します。
問題の総数が200,000を超えない場合、次の出力 行は問題を解決するための最適な順序を示します。各行のスペースで区切られた2つの整数は、この問題に必要なリソースユニットの数と、問題を提供した科学者の数を表します。
サンプル入力
2
2 1 1 1 10
2 3 1 1 10
サンプル出力
0
1 1
2 1
3 2
4 2
データサイズと規則
20データの% N = 2、1≤ kはI ≤2000;
データの別の30% N ≤、= 2を1 kはI ;≤200000
データ1の残りの50%≤ N ≤5000、1≤ k個のI ≤5000。
分析:各科学者の問題について:1。悪いペアに遭遇する前に問題の各グループを結合し、すべての科学者が悪いペアに遭遇する前に問題の各グループを結合し(昇順)、それらをマージして並べ替えます(安定した並べ替え)この方法は配列の順序には影響しません)02。科学者の問題が解決するまで、最初の手順を繰り返します。
今日は少し疲れました。コードを入れましょう。でも70点だったので、なぜそうしなかったのかわからないので、明日チェックします。(正しいコードは以下のとおりです)。
package March;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Question11 {
//Beaver's Calculator
final static int maxn=5100;
static class t{
int pos,count;//pos:当前的位置,count:某一个科学家的问题数
long p[]=new long [maxn+5];//科学家对应问题的资源数 从一开始
}
static t q[]=new t[maxn+5];//保存每个科学家的问题情况
static class s{//安排的对应情况
int id;//对应的科学家
long key;//需要的资源
}
static s R[]=new s[40*maxn+5];//安排
static s R1[]=new s[40*maxn+5];
static void init()//初始化
{
for(int i=0;i<maxn+5;i++)
q[i]=new t();
for(int i=0;i<40*maxn+5;i++)
{
R[i]=new s();
R1[i]=new s();
}
}
static void Merge(int s,int m,int t)
{
int i,j,k;
i=s;//R1第一个序列的始点
j=m+1;//R1第二个序列的始点
k=s;//R的始点
while(i<=m&&j<=t)
{
if(R1[i].key<R1[j].key)//从小到大
R[k++]=R1[i++];
else
R[k++]=R1[j++];
}
while(i<=m) R[k++]=R1[i++];//如果R1第二个序列先排完
while(j<=t) R[k++]=R1[j++];//如果R1第一个序列先排完
for(i=s;i<k;i++)
R1[i]=R[i];//将拍好序列的元素再赋值给R1
}
static void Msort(int s,int t)//二分法归并
{
if(s<t)
{
int m=(s+t)/2;
Msort(s,m);
Msort(m+1,t);
Merge(s,m,t);
}
}
public static void main(String[] args) throws IOException {
int n,k,r,x,y,m;
int length=0;
int ans=-1;
int start=0,end=0;
BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in));//加快输入
String str=bfr.readLine();
String S[]=str.split(" ");
n=Integer.parseInt(S[0]);
init();
for(int i=1;i<=n;i++)
{
str=bfr.readLine();
S=str.split(" ");
k=Integer.parseInt(S[0]);
r=Integer.parseInt(S[1]);
x=Integer.parseInt(S[2]);
y=Integer.parseInt(S[3]);
m=Integer.parseInt(S[4]);
int sum=0;
length+=k;
q[i].pos=1;//现在的位置
q[i].count=k;//科学家i的问题总数
q[i].p[1]=r;//第一个问题所需资源数
for(int j=2;j<=k;j++)
{
q[i].p[j]=(x*q[i].p[j-1]+y)%m;
if(q[i].p[j]<q[i].p[j-1])
sum++;
}
ans=Math.max(ans, sum);
//我们所需要求的最优顺序下最少的“坏对”个数,就是所有科学家所提出的问题的序列中的最多“坏对”的个数,即为所求。
}
System.out.println(ans);
if(length<=200000)//依题意
{
while(end<length)//从0开始
{
for(int i=1;i<=n;i++)
{
int j;
for( j=q[i].pos;j<=q[i].count;j++)
{
if(j!=q[i].pos&&q[i].p[j]<q[i].p[j-1])//发现坏对
{
q[i].pos=j;
break;//跳出循环 破坏之 求的都是升序段
}
R1[end].id=i;
R1[end++].key=q[i].p[j];
}
if(j>q[i].count)
q[i].pos=j;//已完,科学家i的问题不在参与循环
}
Msort(start,end-1);//对所有科学家的升序段进行排序不会改变某一个科学家问题排列的相对位置。随便举个例子就OK啦,
//end-1是因为 前面的是end++ 后自增,所以结束时,其大小要比数组最后一个有意义的值的序列值要大1
start=end;//同理 ,开始下一段
}
for(int i=0;i<length;i++)
System.out.println(R1[i].key+" "+R1[i].id);
}
}
}
評価の詳細:
詳細記録 |
|
数日間考えてみたところ、何が悪いのかわかりませんでした。3月11日まで、突然、動作エラーの30%がいつもと同じではないことに気づきました。それなら、他の理由があるはずです。バイドゥは、配列が範囲外なので、さまざまな変更、エラー~~~、最終的にデータサイズを確認します
データサイズと規則
20データの% N = 2、1≤ kはI ≤2000;
データの別の30% N ≤、= 2を1 kはI ;≤200000
データ1の残りの50%≤ N ≤5000、1≤ k個のI ≤5000。
次に、kiは最大200,000になる可能性があるため、tのp配列が5005に開かれているため、tが間違っていることがわかりました。これは悪くありません。
その後、p配列のサイズを200005に変更しました。合格したと思いましたが、メモリがオーバーランしました。Ir、詳しく見てみましょう。eh、n = 2、hehehe、特殊なケースの説明、
if(n == 2){} else {}、送信後、ac、hahaha、
コードは次のように表示されます。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//100points
public class Main {
//Beaver's Calculator
final static int maxn=5000;
static class t{
int pos,count;//pos:当前的位置,count:某一个科学家的问题数
long p[]=new long [maxn+5];//科学家对应问题的资源数 从一开始
}
static class T2{
int pos,count;//pos:当前的位置,count:某一个科学家的问题数
long p[]=new long [200005];//科学家对应问题的资源数 从一开始
}
static t q[];//保存每个科学家的问题情况
static T2 Q[];//n=2时 p[i] i=200005很大 会炸内存,必须先搞出来
static class s{//安排的对应情况
int id;//对应的科学家
long key;//需要的资源
}
static s R[]=new s[200005];//安排
static s R1[]=new s[200005];
static void init(int n)//初始化
{
if(n==2)//分类讨论
{
Q=new T2[3];
for(int i=1;i<=n;i++)//从1开始计数
Q[i]=new T2();
}
else
{
q=new t[n+1];
for(int i=1;i<=n;i++)
q[i]=new t();
}
for(int i=0;i<200005;i++)
{
R[i]=new s();
R1[i]=new s();
}
}
static void Merge(int s,int m,int t)
{
int i,j,k;
i=s;//R1第一个序列的始点
j=m+1;//R1第二个序列的始点
k=s;//R的始点
while(i<=m&&j<=t)
{
if(R1[i].key<R1[j].key)//从小到大
R[k++]=R1[i++];
else
R[k++]=R1[j++];
}
while(i<=m) R[k++]=R1[i++];//如果R1第二个序列先排完
while(j<=t) R[k++]=R1[j++];//如果R1第一个序列先排完
for(i=s;i<k;i++)
R1[i]=R[i];//将拍好序列的元素再赋值给R1
}
static void Msort(int s,int t)//二分法归并
{
if(s<t)
{
int m=(s+t)/2;
Msort(s,m);
Msort(m+1,t);
Merge(s,m,t);
}
}
public static void main(String[] args) throws IOException {
int n,r,k,x,y,m;
int length=0;
int ans=-1;
int start=0,end=0;
BufferedReader bfr=new BufferedReader(new InputStreamReader(System.in));
//加快输入
String str=bfr.readLine();
String S[]=str.split(" ");
n=Integer.parseInt(S[0]);
init(n);
for(int i=1;i<=n;i++)
{
str=bfr.readLine();
S=str.split(" ");
k=Integer.parseInt(S[0]);
r=Integer.parseInt(S[1]);
x=Integer.parseInt(S[2]);
y=Integer.parseInt(S[3]);
m=Integer.parseInt(S[4]);
int sum=0;
length+=k;
if(n==2)
{
Q[i].pos=1;//现在的位置
Q[i].count=k;//科学家i的问题总数
Q[i].p[1]=r;//第一个问题所需资源数
for(int j=2;j<=k;j++)
{
Q[i].p[j]=(Q[i].p[j-1]*x+y)%m;
if(Q[i].p[j]<Q[i].p[j-1])
sum++;
}
}
else
{
q[i].pos=1;//现在的位置
q[i].count=k;//科学家i的问题总数
q[i].p[1]=r;//第一个问题所需资源数
for(int j=2;j<=k;j++)
{
q[i].p[j]=(q[i].p[j-1]*x+y)%m;
if(q[i].p[j]<q[i].p[j-1])
sum++;
}
}
ans=Math.max(ans, sum);
//我们所需要求的最优顺序下最少的“坏对”个数,就是所有科学家所提出的问题的序列中的最多“坏对”的个
//数,即为所求。
}
System.out.println(ans);
if(length<=200000)//依题意
{
while(end<length)//从0开始
{
if(n==2)
{
for(int i=1;i<=n;i++)
{
int j;
for( j=Q[i].pos;j<=Q[i].count;j++)
{
if(j!=Q[i].pos&&Q[i].p[j]<Q[i].p[j-1])//发现坏对
{
Q[i].pos=j;
break;//跳出循环 破坏之 求的都是升序段
}
R1[end].id=i;
R1[end++].key=Q[i].p[j];
}
if(j>Q[i].count)
Q[i].pos=j;//已完,科学家i的问题不在参与循环
}
}
else
{
for(int i=1;i<=n;i++)
{
int j;
for( j=q[i].pos;j<=q[i].count;j++)
{
if(j!=q[i].pos&&q[i].p[j]<q[i].p[j-1])//发现坏对
{
q[i].pos=j;
break;//跳出循环 破坏之 求的都是升序段
}
R1[end].id=i;
R1[end++].key=q[i].p[j];
}
if(j>q[i].count)
q[i].pos=j;//已完,科学家i的问题不在参与循环
}
}
Msort(start,end-1);
//对所有科学家的升序段进行排序不会改变某一个科学家问题排列的相对位置。随便举个例子就OK啦,
//end-1是因为 前面的是end++ 后自增,所以结束时,其大小要比数组最后一个有意义的值的序列值要大1
start=end;//同理 ,开始下一段
}
for(int i=0;i<length;i++)
System.out.println(R1[i].key+" "+R1[i].id);
}
}
}
評価の詳細:
詳細記録 |
|
総括する:
1.実際、この質問はそれほど難しくありません。つまり、一部のデータに問題があります。次にエラーを修正するときは、最初にエラーの種類を特定してから、適切な薬を処方する必要があります。間違えないでください。そうしないと、時間の無駄になります。(Lanqiaoカップの実行エラーは一般的に範囲外のインデックスグループです)
2.問題が発生した場合は、落ち着いて分析し、安定してください。
3.数日間の絡み合いの後、問題を解決するのは素晴らしい気分です。!!