CXMS 瞎几把胡策题 ROUDN1
T1 :
修复道路 (path.cpp) 时限:2s 内存:128MB 题目描述 夜深了,xcy正做着美梦((~﹃~)~zZ)…… 20年后,xcy成为了伟大的设计建筑家。他所在的城市有N个区域,这些区域是通过M条道路连接的(然而这些道路都已损坏),每条道路都有一定的长度。市长希望他将一些道路修复(各个区域可能并不连通),使得任意一个区域能互相连通。此外市长还希望有且仅有K个区域与市政府(节点1)连通,并且使得路径和最小。 xcy一脸懵逼,便来求助于你了 输入格式 第一行三个整数N,M,K。其中N为城市的区域数,M为道路数量,K为与市政府连通的道路数(可能有重边)。 第2至M+1行每行两个整数ui,vi和一个实数wi,表示ui与vi之间有一条长度为wi的道路。 输出格式 共一行,两个整数,表示最小路径和。 若不存在这样的情况,输出-1。 输入样例1 4 5 2 1 2 1 2 3 1 3 4 1 1 3 3 1 4 2 输出样例1 4 样例说明1 选1、2、5(或1、3、5)三条边。 输入样例2 8 10 2 1 2 1 1 3 2 1 4 3 1 5 4 2 6 5 6 7 2 3 7 3 4 7 3 3 8 3 5 8 1 输出样例2 15 数据规模 100%的数据: 1 ≤ n ≤ 5000; 0 ≤ m ≤ 100000; 0 ≤ k < 5000; 1 ≤ ui, vi ≤ n;; 1 ≤ wi ≤ 100000
SOL: 本来想着把1弄走后跑树上背包的,脑子一抽没写出来(也不知道对不对。虽然不保证生成树唯一,但拟阵有很多优秀的性质,说不定是对的,反正学弟出的题,也不会卡这个对不对)。 然后STD是wqs 二分。
(⊙o⊙)… 后生可畏。
#include<bits/stdc++.h> #define eho(x) for(int i=head[x];i;i=net[i]) #define N 400007 #define sight(c) ('0'<=c&&c<='9') #define v fall[i] #define exp 1e-6 #define inf (1<<28) #define db double using namespace std; #define M 8007 int fp[M],f[N],fall[N],net[N],cost[N],head[M],tot,usd[N]; int n,m,k,x,y,w,fx,fy,Tot; struct Node{ int id,x,cc,ud; inline bool operator <(const Node&X)const{ return x==X.x?cc>X.cc:x<X.x; } }p[N]; struct Eg{ db w; int x,y; inline bool operator <(const Eg&X)const{ return w<X.w; } }e[N]; inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } int getfa(int x){ return f[x]==x?x:f[x]=getfa(f[x]); } int rr; db anw; bool check(db x) { rr=0; anw=0; for (int i=1;i<=n;i++) f[i]=i; for (int i=1;i<=Tot;i++) if (e[i].x==1) e[i].w+=x; sort(e+1,e+Tot+1); for (int i=1;i<=Tot;i++) { fx=getfa(e[i].x); fy=getfa(e[i].y); if (fx==fy) continue; f[fx]=fy; anw+=e[i].w; if (e[i].x==1) rr++; } for (int i=1;i<=Tot;i++) if(e[i].x==1) e[i].w-=x; return rr<=k; } int der; #define Mid ((L+R)*0.5) signed main() { freopen("path.in","r",stdin); freopen("path.out","w",stdout); // read(n); read(m); read(k); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) f[i]=i,p[i].id=i,p[i].x=inf; for (int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&w); if (x>y) swap(x,y); e[++Tot].x=x,e[Tot].y=y,e[Tot].w=w; if (e[Tot].x==1) der++; } cerr<<der<<' '<<k<<endl; if ((k==0&&n>1)||der<k||(m<n-1)) {writeln(-1); return 0;} check(0); int ft=getfa(1); for (int i=2;i<=n;i++) if (ft^getfa(i)) { writeln(-1); return 0; } db L,R; L=-1000000; R=1000000; while (R-L>exp) if (check(Mid)) R=Mid; else L=Mid; check(R); if (Mid<-100000||Mid>100000) { writeln(-1); return 0; } cerr<<k<<" "<<rr<<endl; writeln(anw-k*L+10*exp); return 0; }
T2 :
小朋友的难题 question.cpp 时限:2 Sec 内存:512MB 题目描述 上周,xcy参加了全国小学生综合素养竞赛。令他始料未及的是,他得了倒数第二名。面对小朋友们的嘲笑,他来向你求助,希望你能帮他解决考试中最难的一题。 题目是这样的:给你N个长度相同的字符串(由小写字母和’?’组成),s1,s2…,sn。求与这N个串中刚好K个串匹配的字符串T的个数(答案模1000003)。 若字符串sx(1<=x<=N) 和T匹配,满足以下条件: 1. Sx.length=T.length. 2. 对于任意1<=i<=sx.length,满足sx[i]=’?’或sx[i]=T[i],其中T只包含小写字母。 输入格式 本题包含多组数据。 第一行:一个整数T,表示数据的个数。 对于每组数据: 第一行:两个整数,N和K(含义如题目表述)。 接下来N行:每行一个字符串。 输出格式 如题 输入输出样例 question.in 5 3 3 ???r??? ??????? ??????? 3 4 ??????? ?????a? ??????? 3 3 ??????? ?a??j?? ????aa? 3 2 a?????? ??????? ??????? 3 2 ??????? ???a??? ????a?? question.out 914852 0 0 871234 67018 说明 对于30%的数据,T ≤ 3,M ≤ 5,字符串长度≤ 20; 对于70%的数据,T ≤ 3,M ≤ 16,字符串长度≤ 30; 对于100%的数据,T ≤ 3,M ≤ 21,字符串长度≤ 50。
SOL: 不知道为什么,这道题长得像暴力能过的样子,然后就过了。类似容斥一样的东西,那个转移系数自己算一下就好了。
我甚至没卡常,可能是数据友好吧。
#pragma GCC optimize("-Ofast") #include<bits/stdc++.h> #define mo 1000003 using namespace std; char ch[23][53],cp; int anw,p,n,m,a[23],T,len,op; long long ans,c[23][23],opp[23]; void work() { anw=1; for (int i=1;i<=len;i++) { p=26; for (int j=1;j<=op;j++) if (ch[a[j]][i]!='?') { if (p==26) p=1,cp=ch[a[j]][i]; else if (p==1&&cp!=ch[a[j]][i]) return; } anw=anw*p%mo; } ans+=opp[op]*anw%mo; } void dfs(int x){ if (x==n+1) { if (op<m) return; work(); return; } a[++op]=x; dfs(x+1); op--; dfs(x+1); } signed main () { freopen("question.in","r",stdin); freopen("question.out","w",stdout); for (int i=1;i<=22;i++) { c[i][0]=c[i][i]=1; for (int j=1;j<i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo; } // for (int i=1;i<=) scanf("%d",&T); while (T--) { memset(opp,0,sizeof opp); scanf("%d%d",&n,&m); ans=0; for (int i=1;i<=n;i++) scanf("%s",ch[i]+1); len=strlen(ch[1]+1); opp[m]=1; for (int i=m+1;i<=n;i++) { for (int j=m;j<i;j++) opp[i]-=c[i][j]*opp[j]%mo; opp[i]=opp[i]%mo; } dfs(1); printf("%lld\n",(ans%mo+mo)%mo); } return 0; }
T3 :
买彩票(lottery.cpp) 时限:1s 内存:512MB 题目背景 婷婷是一个热衷于买彩票的女孩子。 题目描述 今天,婷婷又去买彩票了。彩票号码的长度为n,所有由0-9的数字组成的n位号码都可以购买,但只有一张是中奖号码。根据她以往的经验,她可以确定所有含有长度为m的不吉利序列的彩票号码是不可能中奖的。 但即使这样,她的中奖概率仍然很低。于是她找来了cqh。cqh可以使用念力。当可能的彩票数量大于k时,他可以排除k张不会中奖的彩票。这个操作可以经行多次,直到剩余的可能的彩票数量小于等于k。 婷婷每次只会买一张彩票,现在她想知道她中奖的概率有多少,我们认为每张未被确认为不可能中奖的彩票中奖概率相等,这次只有一张彩票会中奖。并且每张彩票只有中奖与不中奖这两种可能。 输入格式 第一行有四个数n,m,k,l。l表示婷婷希望概率能精确到小数点后l位 第二行是一个m位的数字序列,表示不吉利序列 输出格式 婷婷中奖的概率 输入样例 4 3 100 23 111 输出样例 0.01234567901234567901235 数据范围 30%数据N<=1000 90%数据N<=1000000 100%的数据N<=10^10,M<=20,K<=10000,L<=10000;
SOL :就是一个很简单的DP呢,也没有特征向量优化矩阵幂。还写残了,只能感叹自己老了。
#include <bits/stdc++.h> using namespace std; #define oo 0x3f3f3f3f #define mp make_pair #define fi first #define se second #define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr) #define FO(i,a,b) for (int i=(a);i<=(b);++i) #define FD(i,a,b) for (int i=(a);i>=(b);--i) #define LL long long template <class T> inline bool chkmin(T& x, T y) { return x > y ? x = y, true : false; } template <class T> inline bool chkmax(T& x, T y) { return x < y ? x = y, true : false; } inline LL read(void) { LL x, f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; return x * f; } LL n; int m,MO,l,nxt[25]; int a[10005]; char s[25]; int get(int x){ FD(i,x-1,1){ bool flag=1; FO(j,1,i) if (s[j]!=s[x-i+j]) { flag=0; break; } if (flag) return i; } return 0; } int C[21][21],M[21][21],A[21][21]; void mul(int A[21][21],int B[21][21]){ FO(i,0,m)FO(j,0,m){ C[i][j]=0; FO(z,0,m) (C[i][j]+=1ll*A[i][z]*B[z][j]%MO)%=MO; } memcpy(A,C,sizeof(C)); } int main() { freopen("lottery.in","r",stdin); freopen("lottery.out","w",stdout); n=read();m=read();MO=read();l=read(); scanf("%s",s+1); M[0][0]=9,M[0][1]=1; FO(i,1,m-1){ FO(ch,'0','9'){ if (ch==s[i+1]) {M[i][i+1]++;continue;} int rc=-1; FD(j,i,1){ if (ch!=s[j]) continue; bool flag=1; FO(z,1,j-1) if (s[z]!=s[i+1-j+z]) { flag=0; break; } if (flag) { rc=j;break; } } if (rc==-1) M[i][0]++; else M[i][rc]++; } } memcpy(A,M,sizeof(M));n--; for (;n;n>>=1){ if (n&1) mul(A,M); mul(M,M); } int ans=0; FO(i,0,m-1) (ans+=A[0][i])%=MO; if (ans==0){ printf("1."); FO(i,1,l) putchar('0'); puts(""); return 0; } printf("0."); LL y=10; FO(i,1,l+1){ if (y<ans) y*=10,a[i]=0; else a[i]=y/ans,(y%=ans)*=10; } if (a[l+1]>=5){ a[l]++; FD(i,l-1,1) a[i]+=a[i+1]/10,a[i+1]%=10; } FO(i,1,l) putchar(a[i]+48); return 0; }