1. 程式人生 > >NOIP賽前模擬20171027總結

NOIP賽前模擬20171027總結

space 因此 沒有 char 決策單調 push 移動 stdout max

題目:

1.壽司

給定一個環形的RB串··要求經過兩兩互換後RB分別形成兩段連續區域,求最少操作次數(算法時間O(n))

2.金字塔

給定一個金字塔的側面圖有n層··已知每一層的寬度··高度均為1··要求在圖中取出恰好K個互不相交的矩形(邊緣可以重疊),求最多可以取出多少面積

n<=20000,k<=100

3.心靈治愈

給定n,m要求取出不大於m的n個正整數,問有多少種取法使n個數和m的最大公因數為1,n,m<=10^15

題解:

1.分析

首先為了方便我們把環從中間斷開看成一個序列,我們考慮如果移動R串··那麽肯定是找到某一B為中心··B的左邊R移到一起··B的右邊R移到一起(這裏描述有點模糊···如果序列左邊的R都移到一起,且序列最左邊為R,右邊同理··則實際在環中R肯定是連續的一段··)

因此我們先隨意找一個B為中心··然後計算答案··之後我們一次將序列最左端的字符移到最右端(比如序列BBRRR移動後就變成BRRRB)然後考慮答案的變化即可···具體實現參見代碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include
<string> #include<algorithm> using namespace std; const int N=2e6+5; int T,n,num[N]; char s[N]; int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); scanf("%d",&T); while(T--) { long long ans=0,cnt=0; int tot1=0,tot2=0,totl=0,totr=0,mid; scanf(
"%s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++) { if(s[i]==B) num[i]=num[i+n]=1,tot1++; else num[i]=num[i+n]=2,tot2++; } int half=(tot1+1)/2;int temp=0; for(int i=1;i<=n;i++) { if(num[i]==1) {temp++;if(temp==half) mid=i;} else { if(temp<half){totl++;cnt+=temp;} else {totr++;cnt+=(tot1-temp);} } } ans=cnt; for(int i=1;i<n;i++) { if(num[i]==1) { int tot=0,j; for(j=mid+1;num[j]!=1;j++) tot++; cnt-=totl;cnt+=(totr-tot);mid=j; totl+=tot;totr-=tot; if(tot1%2==0) cnt-=tot; ans=min(ans,cnt); } else { totl-=1;totr+=1; } } cout<<ans<<endl; } return 0; }

2.dp+決策單調性/斜率優化

dp方程肯定很好想··第一要明確取的方案··我們肯定是以某一層的寬度為矩形的一邊··然後往下取到某一層為一個矩形·矩形的高就是兩層高的差··

然後設f[j][i]為第j塊矩形以第i層為一邊的最大面積··轉移方程即為:

f[j][i]=max(f[j][i],f[k][i-1]+(long long)len[j]*(j-k));

其中k為我們往下枚舉的層數··len為j層的寬度··

然後通過打表(dalao也可以分析)得出該方程滿足決策單調性且使用於斜率優化····這裏兩種方法都能過

決策單調性:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<0||c>9;c=getchar());
  for(;c<=9&&c>=0;c=getchar())  f=(f<<3)+(f<<1)+c-0;
  return f;
}
const int N=20005;
const int M=105;
struct node
{
  int l,r,pos;
}Que[N];
int n,K;
long long len[N],f[N][M];
inline long long calc(int i,int j,int now)
{
  return f[j][now-1]+(long long)len[i]*(i-j);
}
inline int find(node a,int b,int now)
{
  int le=a.l,ri=a.r,ans=a.r+1;
  while(le<=ri)
  {
    int mid=(le+ri)/2;
    if(calc(mid,b,now)>calc(mid,a.pos,now))  ri=mid-1,ans=mid;
    else le=mid+1;
  }
  return ans;
}
inline void dp(int now)
{
  int Head=1,Tail=0;
  node tmp;tmp.l=now;tmp.r=n;tmp.pos=now-1;Que[++Tail]=tmp;
  for(int i=now;i<=n;i++)
  {
    while(Que[Head].r<i)  Head++;
    f[i][now]=calc(i,Que[Head].pos,now);
    if(calc(n,i,now)>calc(n,Que[Tail].pos,now))
    {
      while(Head<=Tail&&calc(Que[Tail].l,i,now)>calc(Que[Tail].l,Que[Tail].pos,now))  Tail--;
      if(Head<=Tail)
      {
        int t=find(Que[Tail],i,now);
        Que[Tail].r=t-1;
        node tmp;tmp.l=t,tmp.r=n,tmp.pos=i;Que[++Tail]=tmp;
      }
      else
      {
        node tmp;tmp.l=i+1;tmp.r=n;tmp.pos=i;Que[++Tail]=tmp;
      }
    }
  }
}
int main()
{
  //freopen("pyramid.out","w",stdout);
  n=R(),K=R();int x,y;
  if(n<=1000)
  {  
    for(int i=1;i<=n;i++)
    {
      x=R(),y=R();len[i]=y-x+1;f[i][1]=(long long)len[i]*i;
    }
    for(int i=2;i<=K;i++)
      for(int j=i;j<=n;j++)
        for(int k=i-1;k<j;k++)  f[j][i]=max(f[j][i],f[k][i-1]+(long long)len[j]*(j-k));
    long long ans=0;
    for(int i=K;i<=n;i++)  ans=max(f[i][K],ans);
    cout<<ans<<"\n";
  }
  else
  {
    for(int i=1;i<=n;i++)
    {
      x=R(),y=R();len[i]=y-x+1;f[i][1]=(long long)len[i]*i;
    }
    for(int i=2;i<=K;i++)
      dp(i);
    long long ans=0;
    for(int i=K;i<=n;i++)  ans=max(f[i][K],ans);   
    cout<<ans<<"\n";
  }
  return 0;
}

3.質因數分解+容斥原理

這道題和之前跳蚤的那道題是一模一樣的··這裏就並不多說了··

唯一註意的是我發現了自己快速冪的一個漏洞··求a^b之前要將a取模···之前一直沒有註意到···還有就是註意最後答案為負的問題

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
vector<long long>zhiyinzi;
const long long mod=1e9+7;
long long n,m,ans=0;
inline long long ksm(long long a,long long b)
{
  long long ans=1;a%=mod;  
  while(b)
  {
    if(b%2==1)  ans=(ans*a)%mod;
    b/=2;a=(a*a)%mod;
  }
  return ans;
}
inline void dfs(int u,long long tot,long long f)
{
  if(u==zhiyinzi.size())
  {
    long long temp=m/tot;
    ans=(ans+f*ksm(temp,n))%mod;
    ans=(ans%mod+mod)%mod;
    return;
  }
  dfs(u+1,tot,f);
  dfs(u+1,tot*zhiyinzi[u],-f);
}
int main()
{
  scanf("%I64d%I64d",&n,&m);
  long long temp=m;
  for(long long i=2;i*i<=m;i++)
  {
    if(i>temp)  break;  
    if(temp%i==0)
    { 
      while(temp%i==0)  temp/=i;
      zhiyinzi.push_back(i);
    }
  }
  if(temp!=1)  zhiyinzi.push_back(temp);
  dfs(0,1,1);
  ans=(ans%mod+mod)%mod;
  cout<<ans<<endl;
  return 0;
}

NOIP賽前模擬20171027總結