B.矩阵快速幂-十进制
-
题目:generator 1
-
链接:https://ac.nowcoder.com/acm/contest/885/B
-
大意:告诉你 x 0 , x 1 , a , b , 且 x i = a ∗ x i − 1 + b ∗ x i − 2 , n ∈ [ 1 , 1 0 1 0 6 ] , m o d , 让 你 求 出 a n % m o d x_0,x_1,a,b,且x_i=a*x_{i-1}+b*x_{i-2},n∈[1,10^{10^6}],mod,让你求出a_n\%mod x0,x1,a,b,且xi=a∗xi−1+b∗xi−2,n∈[1,10106],mod,让你求出an%mod
-
分析:矩阵快速幂就可以,然而矩阵快速幂需要把指数化为二进制,但是这里给出的指数是十进制大数,所以使用10进制版的矩阵快速幂,注意常数优化
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int maxm=1e7+10;
long long x0,x1,a,b,mod;
char o[maxn];
int s[maxn];
int sts=1,ens;
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline bool read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror) return false;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x; return true;
}
inline bool read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror) return false;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x; return true;
}
inline bool read(double &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror) return false;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (ch=='.'){
double tmp=1; ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if (sign)x=-x; return true;
}
inline bool read(char *s){
char ch=nc();
for (;blank(ch);ch=nc());
if (IOerror) return false;
for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0; return true;
}
inline void read(char &c){
for (c=nc();blank(c);c=nc());
if (IOerror){c=-1;return;}
}
//fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(double x,int y){
static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
if (x<-1e-12)out('-'),x=-x;x*=mul[y];
ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i) {}; print(x3);}
}
void println(double x,int y){print(x,y);out('\n');}
void print(char *s){while (*s)out(*s++);}
void println(char *s){while (*s)out(*s++);out('\n');}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void println(int x){Ostream.println(x);}
inline void print(char x){Ostream.out(x);}
inline void println(char x){Ostream.out(x);Ostream.out('\n');}
inline void print(ll x){Ostream.print(x);}
inline void println(ll x){Ostream.println(x);}
inline void print(double x,int y){Ostream.print(x,y);}
inline void println(double x,int y){Ostream.println(x,y);}
inline void print(char *s){Ostream.print(s);}
inline void println(char *s){Ostream.println(s);}
inline void println(){Ostream.out('\n');}
inline void flush(){Ostream.flush();}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace IO;
struct matrix{
ll mat[3][3];int siz;
matrix(int a=3){
siz=a-1;
memset(mat,0,sizeof(mat));
}
matrix operator*(const matrix &b){
matrix res;
for(int i=1;i<=siz;i++){
for(int k=1;k<=siz;k++){
if(mat[i][k]){
for(int j=1;j<=siz;j++){
if(b.mat[k][j]){
res.mat[i][j]=(res.mat[i][j]+(mat[i][k]*b.mat[k][j]));
if(res.mat[i][j]>=mod) res.mat[i][j]%=mod;
}
}
}
}
}
return res;
}
matrix pow(long long k){
matrix res,tmp=*this;
for(int i=1;i<=siz;i++) res.mat[i][i]=1;
while(k){
if(k&1) res=res*tmp;
tmp=tmp*tmp;
k>>=1;
}
return res;
}
void print(){
for(int i=1;i<=siz;i++){
for(int j=1;j<=siz;j++){
printf("%lld%c",mat[i][j],j==siz?'\n':' ');
}
}
}
}cur,d,e,res;
void jianyi()
{
int last=-1;
if(s[ens]>=1) {s[ens]-=1;return;}
else{
for(int i=ens;i>=sts;i--) {
if(s[i]) {s[i]-=1;break;}
else s[i]=9;
}
if(!s[sts]) sts++;
}
}
int main()
{
//freopen("/Users/wzw/Desktop/ACM/1.in","r",stdin);
read(x0);read(x1);read(a);read(b);
read(o+1);read(mod);
ens=strlen(o+1);
for(int i=1;i<=ens;i++) s[i]=o[i]-'0';
jianyi();
cur.mat[1][1]=a;cur.mat[1][2]=b;cur.mat[2][1]=1;cur.mat[2][2]=0;
d.mat[1][1]=x1;d.mat[2][1]=x0;
res.mat[1][1]=res.mat[2][2]=1;
for(int i=ens;i>=sts;i--) {
auto tmp=cur.pow(s[i]);
res=res*tmp;
cur=tmp*cur.pow(10-s[i]);
}
res=res*d;
printf("%lld\n",res.mat[1][1]);
}
C.BSGS-略作修改
-
题目:generator 2
-
链接:https://ac.nowcoder.com/acm/contest/885/C
-
大意:给出 a , x 0 , b , p a,x_0,b,p a,x0,b,p,告诉你 x i = ( a ∗ x i − 1 + b ) m o d p x_i=(a*x_{i-1}+b)mod\ p xi=(a∗xi−1+b)mod p,给你Q(1000)个询问,每个询问包含一个v(1e18),问你最小的 i , 使 得 x i = v i,使得x_i=v i,使得xi=v
-
分析:a=0特例特判下,a!=0可以先根据高中知识求出通项公式,转化为一个bsgs的问题但是bsgs传统分块方式都是分成 n ∗ n \sqrt n*\sqrt n n∗n的,而bsgs的初始化复杂度为 n B l o c k nBlock nBlock,查询复杂度szBlock,所以这题查询比较多,有选择地决定快的大小就可以了。
#include<bits/stdc++.h>
#include<unordered_map>
typedef long long ll;
const int maxn = 1e7 + 7;
const int inf = 0x3f3f3f3f;
using namespace std;
ll n, x0, a, b, mod;
ll invb, inva;
ll qpow(ll x, ll n)
{
ll res = 1;
while (n)
{
if (n & 1) res = res * x%mod;
x = x * x%mod; n >>= 1;
}
return res;
}
unordered_map<int, int>ma;
ll bsgs(ll a, ll b, ll p) {
if (b == 1) return 0;
int res = inf;
for (int i = 0; i <= 999; i++) {
//int id = find(b);
auto id = ma.find(b);
if (id != ma.end()) res = min(res, id->second - i);
b = b * a%p;
}
if (res == inf) return -1;
return res;
}
void init_bsgs()
{
int st = qpow(a, 1000), x = 1;
for (int i = 1; i <= 1000001; i++)
{
x = (ll)x*st%mod;
if (ma.find(x)==ma.end()) ma[x]=i * 1000;
}
}
int main()
{
int T; scanf("%d", &T);
while (T--)
{
scanf("%lld%lld%lld%lld%lld", &n, &x0, &a, &b, &mod);
ma.clear();
int q; scanf("%d", &q); init_bsgs();
ll tmp = qpow((a - 1 + mod) % mod, mod - 2)*b%mod;
ll inv = qpow((x0 + tmp) % mod, mod - 2);
invb = qpow(b, mod - 2);
while (q--)
{
ll v; scanf("%lld", &v);
if (a == 0)
{
if (v == x0) puts("0");
else if (v == b)
{
if (n != 1) puts("1");
else puts("-1");
}
else puts("-1");
continue;
}
if (a == 1)
{
if (b == 0)
{
if (v == x0) puts("0");
else puts("-1");
}
else
{
ll res = (v - x0 + mod) % mod*invb%mod;
if (res < n) printf("%lld\n", res);
else puts("-1");
}
continue;
}
ll B = (v + tmp) % mod*inv%mod;
ll res = bsgs(a, B, mod);
if (res == -1 || res >= n) puts("-1");
else printf("%lld\n", res);
}
}
return 0;
}
E.子集最大独立集size之和
-
题目:independent set 1
-
链接:https://ac.nowcoder.com/acm/contest/885/E
-
大意:给定一张最多26结点的图,求所有子集的最大独立集size之和
-
分析: 比赛的时候完全没想到怎么做,后来看题解说是状压dp就完了,但无奈我太菜,不会这个状压dp。这题算是考研ACM的功底吧。设A是图中的一个点集,我们要遍历图的所有子集,所以在计算A之前,我们已经计算出了所有A的子集(别问为什么),设p是A中的一个点,则A的答案中要么包含p,要么不包含p,于是—>dp[A]=max(dp[A中除去p和与p有邻边的点]+1,dp[A中除去p]),A中除去p好说,用A的状压减去(1<<p)就好了,但是如何得到[A中除去p和与p有邻边的点]的状压呢,可以算出所有与p点有临边的点集的状压ban,那么[A中除去p和与p有邻边的点]就等于A & (~(ban|(1<<p))),于是可以写代码了,
#include<bits/stdc++.h>
#define F(i,a,b) for(int i=(a);i<=int(b);++i)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = int(27);
typedef unsigned char si;
int ban[maxn];
int n, m;
si dp[1 << 26];
int lowbit(int x) { return x & -x; }
int lowbit2(int x)
{
int p = 0, w = 1;
while ((x&w) == 0)
{
w <<= 1;
++p;
}
return p;
}
#define endl '\n'
int main()
{
#ifndef endl
freopen("C:\\Users\\VULCAN\\Desktop\\data.in", "r", stdin);
cout << "************************************Local Test*********************************" << endl;
#endif // !endl
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T(1), cas(0);
while (cas, T--)
{
cin >> n >> m;
F(i, 0, n - 1)ban[i] = 1 << i;
F(i, 1, m)
{
int a, b; cin >> a >> b;
ban[a] |= 1 << b;
ban[b] |= 1 << a;
}
int ans = 0;
F(i, 1, (1 << n) - 1)
{
auto tmp = dp[i &(~ ban[lowbit2(i)])];
dp[i] = max(dp[i - lowbit(i)], ++tmp);
ans += dp[i];
}
cout << ans << '\n';
}
return 0;
}
//What to Debug
/*
-1.最好把全部warning都X掉,否则:https://vjudge.net/solution/19887176
0.看看自己是否有可能需要快读,禁endl
1.数组越界,爆int,浮点精度(查看精度是否达到题目要求,看有没有浮点数比较:eps),取模操作,初始化数组,边缘数据,输出格式(cas),强制在线是否更新了las
2.通读代码,代码无逻辑错误
3.读题,找到题意理解失误或算法错误
4.放弃
*/
F. 最大团-二分图-输出方案
-
题目:maximum clique 1
-
链接:https://ac.nowcoder.com/acm/contest/885/F
-
大意:给一个集合(大小5e3),由于是集合,所以每个字都不同,求一个最大子集合使得子集合内每两个点最少有1个二进制bit位不同
-
分析:额,对于集合内没对bit位有>=1个不同的,在两点之间连一条边,于是题目就变成了在图论中求一个最大团,但是最大团不是NPC问题么,只能指数级别算呀,这可不行。于是可以看这个边有什么性质,图里的边要满足bit差异至少有1个,那么由于元素不同,它反过来就是bit位差异为1,那么补图的某一边存在当且仅当bit差异为1,相当于就是求补图的最大独立集,再想想,bit差异为1????,那岂不是可以根据二进制中1的个数划分为二分图,二分图的最大独立集???那就可以做了,顺便说下我的二分图板子没有给方案的,还得弄弄。
-
cyy的代码:
#include <bits/stdc++.h>
using namespace std;
int n;
int a[5000],c[5000];
vector <int> g[5000];
void color(int u,int rt) {
for (auto v:g[u]) {
if (v == rt) continue;
if (~c[v]) continue;
c[v] = c[u] ^ 1;
color(v,u);
}
}
bool s[5000],t[5000];
int l[5000],r[5000];
bool dfs(int u) {
s[u] = true;
for (auto v:g[u]) {
if (t[v]) continue;
t[v] = true;
if (l[v] == -1 || dfs(l[v])) {
l[v] = u;
r[u] = v;
return true;
}
}
return false;
}
void work() {
memset(l,-1,sizeof(l));
memset(r,-1,sizeof(r));
int match = 0;
for (int i=0;i<n;i++) if (c[i] == 0) {
memset(t,false,sizeof(t));
match += dfs(i);
}
memset(s,false,sizeof(s));
memset(t,false,sizeof(t));
for (int i=0;i<n;i++) if (c[i] == 0 && r[i] == -1) dfs(i);
printf("%d\n",n-match);
for (int i=0;i<n;i++) {
if ( (c[i] == 0 && s[i]) || (c[i] == 1 && !t[i])) printf("%d ",a[i]);
}
printf("\n");
}
int main() {
memset(c,-1,sizeof(c));
scanf("%d",&n);
for (int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n);
n = unique(a,a+n) - a;
for (int i=0;i<n;i++)
for (int j=0;j<i;j++)
if (__builtin_popcount(a[i] ^ a[j]) == 1) {
g[i].push_back(j);
g[j].push_back(i);
}
for (int i=0;i<n;i++) if (c[i] == -1) {
c[i] = 0;
color(i,-1);
}
work();
return 0;
}
I.几何-三角形
-
题目:three points 1
-
链接:https://ac.nowcoder.com/acm/contest/885/I
-
大意:给你w,h,a,b,c∈[1,50],要你在w*h的矩形框内,找个三角形三边长为a,b,c
-
分析:几何白痴,不多说了,直接给队友代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
#define pi acos(-1.0)
int sgn(double k)
{
return k<-eps?-1:(k<eps?0:1);
}
void print(double a) //数值a保留5位四舍五入输出,
{
char buffer[1000];
sprintf(buffer+1,"%.10lf",a); //
int len=strlen(buffer+1);
bool ok=false;
for(int i=1;i<=len;i++) if(!(buffer[i]=='.'||buffer[i]=='0'||buffer[i]=='-')) {ok=true;break;}
if(ok) printf("%s",buffer+1);
else printf("%.10lf",0.0); //
}
typedef struct point{ //点结构体
double x,y;
point(double a=0,double b=0) {
x=a;y=b;
}
point operator+(point other) {
return point(x+other.x,y+other.y);
}
point operator-(point other) {
return point(x-other.x,y-other.y);
}
point operator*(double k) {
return point(x*k,y*k);
}
double dot(point other) { //点乘,即数量积,内积(ABcos &)
return x*other.x+y*other.y;
}
double cha(point other) { //叉乘,即向量积,外积(ABsin &)
return x*other.y-y*other.x;
}
bool onseg(point p1,point p2) {//判断q是否在线段p1-p2上
point q=*this;
return sgn((p1-q).cha(p2-q))==0&&(p1-q).dot(p2-q)<=0;
}
friend double dis(point p1,point p2) { //计算两点距离
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
friend point intersect(point p1,point p2,point q1,point q2) {//计算直线p1-p2是否与直线q1-q2的交点
return p1+(p2-p1)*((q2-q1).cha(q1-p1)/(q2-q1).cha(p2-p1));
}
friend bool parallel(point p1,point p2,point q1,point q2) { //判断线段p1-p2是否与线段q1-q2平行,重合也会返回true
return sgn((q2-q1).cha(p2-p1))==0;
}
friend bool parallel_intersect(point p1,point p2,point q1,point q2) { //判断线段p1-p2和线段q1-q2在平行的情况下是否重合
return p1.onseg(q1,q2)||p2.onseg(q1,q2)||q1.onseg(p1,p2)||q2.onseg(p1,p2);
}
friend point extend(point p,double len) { //将向量p长度变为len返回一个新的向量,方向不变
if(sgn(dis(point(0,0),p))==0) return point(0,len);
return point(p*(len/dis(point(0,0),p)));
}
void print() {
printf("x:%.3lf y:%.3lf\n",x,y);
}
}Vector;
point rotate(point p1,point p2,double a) //点p2绕着点p1顺时针方向旋转a角度,a为弧度,返回新的point
{
point vec=p2-p1;
double xx=vec.x*cos(a)+vec.y*sin(a);
double yy=vec.y*cos(a)-vec.x*sin(a);
return point(p1.x+xx,p1.y+yy);
}
bool valid(point p1,double w,double h)
{
return sgn(p1.x)>=0&&sgn(p1.x-w)<=0&&sgn(p1.y)>=0&&sgn(p1.y-h)<=0;
}
point ans[3];
bool check(double w,double h,double x,double y,double z,int a,int b,int c)
{
if(sgn(sqrt(w*w+h*h)-x)<0) return false;
double angle_y=acos((x*x+z*z-y*y)/(2*x*z));
if(sgn(x-w)<=0) {
Vector cur=extend(Vector(x,0),z);
ans[a]=point(x,0);ans[c]=point(0,0);ans[b]=cur;
point res=rotate(ans[c],ans[b],2*pi-angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
}else{
double he=sqrt(x*x-w*w);
Vector cur=extend(Vector(w,he),z);
ans[a]=point(w,he);ans[c]=point(0,0);ans[b]=cur;
point res=rotate(ans[c],ans[b],angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
res=rotate(ans[c],ans[b],2*pi-angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
}
if(sgn(x-h)<=0) {
Vector cur=extend(Vector(0,x),z);
ans[a]=point(0,x);ans[c]=point(0,0);ans[b]=cur;
point res=rotate(ans[c],ans[b],angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
}else {
double he=sqrt(x*x-h*h);
Vector cur=extend(Vector(he,h),z);
ans[a]=point(he,h);ans[c]=point(0,0);ans[b]=cur;
point res=rotate(ans[c],ans[b],angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
res=rotate(ans[c],ans[b],2*pi-angle_y);
if(valid(res,w,h)) {ans[b]=res;return true;}
}
return false;
}
void outt()
{
for(int i=0;i<=2;i++) {
print(ans[i].x);printf(" ");
print(ans[i].y);printf(i==2?"\n":" ");
}
}
int main()
{
int t;scanf("%d",&t);
while(t--) {
double w,h,a,b,c;scanf("%lf %lf %lf %lf %lf",&w,&h,&a,&b,&c);
if(check(w,h,a,b,c,0,2,1)) {outt();continue;}
if(check(w,h,a,c,b,1,2,0)) {outt();continue;}
if(check(w,h,b,a,c,0,1,2)) {outt();continue;}
if(check(w,h,b,c,a,2,1,0)) {outt();continue;}
if(check(w,h,c,a,b,1,0,2)) {outt();continue;}
if(check(w,h,c,b,a,2,0,1)) {outt();continue;}
assert(false);
}
}