洛谷P4749 【[CERC2017]Kitchen Knobs】
简明题意如下:
有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; }