1. 程式人生 > >洛谷P4749 【[CERC2017]Kitchen Knobs】

洛谷P4749 【[CERC2017]Kitchen Knobs】

inline 兩個 多少 clas getchar max 最終 同事 adl

簡明題意如下:

有n個轉盤,每個轉盤上都有著7個數字(1~9),現在每次可以選定一個區間[L,R],將區間內的轉盤順時針同事轉動若幹次,使每個轉盤在最後的時候本身所表示的數字最大(數字表示形式:轉盤上小三角所指向的數字為七位數的最高位,然後順時針依次順位),問最少要選多少個區間才能滿足結果。

首先,我們可以通過題面所給的數據,想到可以將此題從一個轉盤轉化為對一個數列進行操作。不難發現:每個轉盤所到達最終狀態的旋轉次數,要麽是確定的,要麽怎麽轉都可以(所有數一致)。所以我們可以將題目轉化為:

  • 每個轉盤應轉動的次數為ai。
  • 每次可以選擇一個區間,加上一個相同的數,使得最終ai%7=0
  • 求出最少的選定區間次數

將問題轉化於此之後,你可能會想到 玩具積木 這道題,然而這兩者是有很大的區別的,在這裏不過多提出。

現在,我們可以將a進行差分操作,將區間+操作也進行差分,則問題又能轉化為:

  • 每次選取兩個數,一個加上k,一個減去k
  • 用最少的操作次數讓所有數mod7等於0

到這步後,顯然我們可以設一個b(i)=a(i)-a(i-1)。將區間操作化為點的操作。把bi分成盡量多的組,使每一組的和等於0,原題的答案也就等於n-組數。

無視0,那麽一定是16配對,25配對,34配對。這樣處理以後最多還有三種數字A,B,C。問題就又變為:將這些數分成最多的組數,使得每組的和為0。

最後就用dp算出答案即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<queue>
#include<ctime>
#define MAXN 200005
#define ll long long
#define maxn 15
#define maxs 1000005
#define inf 1e9
#define eps 1e-9
using namespace
std; inline char gc() { static char now[1<<16],*S,*T; if (T==S) { T=(S=now)+fread(now,1,1<<16,stdin); if (T==S) return EOF; } return *S++; } inline ll readlong() { ll x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-)f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x*=10; x+=ch-0; ch=getchar(); } return x*f; } inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-)f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x*=10; x+=ch-0; ch=getchar(); } return x*f; } void putint(long long t) { int ans[40]= {0}; for(; t; t/=10)ans[++ans[0]]=t%10; for(; ans[0]; ans[0]--)putchar(0+ans[ans[0]]); putchar(\n); } const int N=505; int n; int a[N]; int A,B,C; int cnt[7]; int x,y,z; int ans,m; int e[N][4]; int f[N][N][N]; int t; int query(){ char s[10]; scanf("%s",s); string Ans=""; for(int i=0;i<7;i++){ Ans.push_back(s[i]); } int mask=1,sum=0; for(int i=1;i<7;i++){ string now=""; for(int j=0;j<7;j++){ now.push_back(s[(i+j)%7]); } if(now==Ans){ mask|=1<<i; sum+=i; } else if(now>Ans){ mask=1<<i; sum=i; Ans=now; } } if(mask!=(mask&(-mask))){ return -1; } return sum; } int main(){ int T=read(); while(T--){ int x=query(); if(x<0){ continue; } a[++n]=x; } if(!n){ printf("0\n"); return 0; } for(int i=n+1;i;i--){ a[i]-=a[i-1]; } for(int i=1;i<=n+1;i++){ a[i]=((a[i]%7+7)%7); } for(int i=1;i<=n+1;i++){ cnt[a[i]]++; } // for(int i=1;i<=7;i++){ // cout<<cnt[i]<<endl; // } while(cnt[1]&&cnt[6]){ cnt[1]--; cnt[6]--; ans++; } A=cnt[1]?cnt[1]:cnt[6]; x=cnt[1]?1:6; while(cnt[2]&&cnt[5]){ cnt[2]--; cnt[5]--; ans++; } B=cnt[2]?cnt[2]:cnt[5]; y=cnt[2]?2:5; while(cnt[3]&&cnt[4]){ cnt[3]--; cnt[4]--; ans++; } // cout<<ans<<endl; C=cnt[3]?cnt[3]:cnt[4]; z=cnt[3]?3:4; for(int i=0;i<=7;i++){ for(int j=0;j<=7;j++){ for(int k=0;k<=7;k++){ if(i+j+k&&(i*x+j*y+k*z)%7==0){ e[m][0]=i; e[m][1]=j; e[m][2]=k; e[m++][3]=i+j+k-1; } } } } for(int i=0;i<=A;i++){ for(int j=0;j<=B;j++){ for(int k=0;k<=C;k++){ if(i+j+k){ int tmp=inf; for(int x=0;x<m;x++){ if(i>=e[x][0]&&j>=e[x][1]&&k>=e[x][2]){ tmp=min(tmp,f[i-e[x][0]][j-e[x][1]][k-e[x][2]]+e[x][3]); } } f[i][j][k]=tmp; } } } } printf("%d\n",ans+f[A][B][C]); return 0; }

洛谷P4749 【[CERC2017]Kitchen Knobs】