UVa11916
来源:互联网 发布:vb 修改批处理 编辑:程序博客网 时间:2024/05/22 15:54
题目链接
简介:
有这样一个题目:给定一个M*N的网格涂上K种颜色,其中B个格子不能涂色,其他每个格子涂一种颜色,同一列中的上下两个相邻格子不能涂相同颜色
给出M,N,B个格子的位置,求出涂色方案R%100000007
这道题是上述问题的逆问题:给出N,K,R,B个格子的位置,
求出最小的M
分析:
虽然M(行数)是未知的,但是我们可以知道ta的最小值:
M=max{不能涂色的格子的行编号}
因此可以把整个网格分成两部分:不可变部分,可变部分
我们一列一列的进行涂色
如果一个格子上一个位置不能涂色,那么ta的颜色就有K种选择
其余的格子都只有K-1种选择
假设不变部分以及可变部分的第一行可行的涂色方案有cnt种
(cnt的求解要稍微麻烦一点)
那么每增加一行,涂色方案都会乘P=(K-1)^N
这样我们就得到一个模方程:
cnt*P^M=R
稍微变形得到:
P^M=R*cnt^-1
直接上bsgs求解即可
tip
当B=0的时候需要特殊求解
时刻判断cnt是不是已经等于r了
交上去是T,拍也拍不起来(数据不好造)
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<map>#include<set>#include<cmath>#define ll long longusing namespace std;const ll mod=100000007;map<ll,int> mp;int n,m,k,r,b,x[1000],y[1000];set<pair<int,int> > po; //方便判断ll KSM(ll x,ll y){ ll t=1; x%=mod; while (y) { if (y&1) t=(t%mod*x%mod)%mod; y>>=1; x=(x%mod*x%mod)%mod; } return t%mod;}int bsgs(ll x,ll z) //x^y=z{ x%=mod; z%=mod; if (x==0&&z==0) return 1; if (x==0) return -1; mp.clear(); ll now=1; ll m=(ll)ceil(sqrt((double)mod)); mp[1]=m+1; for (int i=1;i<m;i++) { now=(now%mod*x%mod)%mod; if (!mp[now]) mp[now]=i; //x^i=now } ll inv=1,tmp=KSM(x,mod-m-1); for (int k=0;k<m;k++) { int i=mp[(z*inv)%mod]; //z*x^-km if (i) { if (i==m+1) i=0; return k*m+i; } inv=(inv%mod*tmp%mod)%mod; } return -1;}ll count(){ int i,j; int c1=0; for (int i=1;i<=b;i++) if (x[i]!=m&&!po.count(make_pair(x[i]+1,y[i]))) //计算不可涂色的方格下面有多少不受限制的方格 c1++; //其中不包含行数大于m的不受限制方格 c1+=n; //第一行都有k种涂法 for (int i=1;i<=b;i++) if (x[i]==1) c1--; //去除不能涂色的方块 int c2=n*m-c1-b; //有k-1种涂色方法的方格 //a=k^c1 * (k-1)^c2 方案数 ll a=(KSM((ll)k,(ll)c1) * KSM((ll)(k-1),(ll)c2))%mod; return a;}int doit(){ ll cnt=count(); if (cnt==r) return m; int c=0; for (int i=1;i<=b;i++) if (x[i]==m) c++; //可变部分中不受限制的方格数 cnt=(cnt * KSM((ll)k,(ll)c))%mod; cnt=(cnt * KSM((ll)(k-1),(ll)(n-c)))%mod; if (cnt==r) return m+1; m++; ll P=KSM((ll)(k-1),(ll)n); ll rr=(r*1LL*KSM(cnt,mod-2))%mod; return bsgs(P,rr)+m;}int main(){ int T; scanf("%d",&T); for (int cas=1;cas<=T;cas++) { m=0; scanf("%d%d%d%d",&n,&k,&b,&r); for (int i=1;i<=b;i++) { scanf("%d%d",&x[i],&y[i]); po.insert(make_pair(x[i],y[i])); if (x[i]>m) m=x[i]; } if (b==0) { ll cnt=KSM((ll)k,(ll)n); if (cnt==r) m=1; else { ll P=KSM((ll)(k-1),(ll)n); ll rr=(r*1LL*KSM(cnt,mod-2))%mod; m=bsgs(P,rr)+1; } printf("Case %d: %d\n",cas,m); } else printf("Case %d: %d\n",cas,doit()); } return 0;}
阅读全文
0 0
- UVa11916
- uva11916(数学题,模方程)
- uva11916 Emoogle Grid
- UVA11916 Emoogle Grid
- uva11916 - Emoogle Grid 网格涂色
- UVA11916 Emoogle Grid 网格涂色 大步小步算法(解模方程对数) 快速幂 模的逆 模的对数
- 桶排序
- Android XRecyclerView简单实现上拉刷新,下拉加载
- unix_timestamp 时间戳函数用法(hive)
- this指针
- PHP的SOAP扩展和websocket
- UVa11916
- 跨域请求接口
- Wireshark进阶之网络问题案例分析
- <PTA>树的同构
- Android 修改默认来电他,通知铃声
- Codeforces Round #432 题解
- laravel5.1 部署到lnmp
- 单链表中是否有环的问题
- [BZOJ2763][JLOI2011]飞行路线(图论)