A BNU ACM校队时间安排表
大水题 开始把数字写错了,WA了一次
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 9 int main() 10 { 11 int cas, n; 12 scanf("%d", &cas); 13 while (cas--) { 14 scanf("%d", &n); 15 if (n==11||n==12) printf("Basic Training\n"); 16 if (n==12) printf("Rookie Contest\n"); 17 if (n==2||n==3||n==4) printf("Spring Training\n"); 18 if (n==4) printf("BNU Contest\n"); 19 if (n==7) printf("Practice Week\n"); 20 if (n==7||n==8) printf("Summer Training\n"); 21 if (n==9||n==10||n==11) printf("Regional Contest\n"); 22 if (n==1||n==5||n==6) printf("Unknown\n"); 23 } 24 return 0; 25 }
B 沙漠之旅
有N种油桶,每种无限桶,选4桶凑成L-X距离,判断能不能凑成。
bool dp[i][j]表示前i距离选了j桶。
if (dp[i][j]) dp[i+a[k]][j+1]=1;
k从1到N。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 bool dp[1001][4]; 9 int a[1001]; 10 int main() 11 { 12 int cas, l, x, n; 13 scanf("%d", &cas); 14 while (cas--) { 15 scanf("%d%d%d", &l, &x, &n); 16 l-=x; 17 memset(dp, 0, sizeof(dp)); 18 dp[0][0]=1; 19 for (int i=1; i<=n; i++) 20 scanf("%d", &a[i]); 21 for (int i=0; i<4; i++) 22 for (int j=1; j<=n; j++) { 23 for (int k=0; k+a[j]<=l; k++) { 24 if (dp[k][i]) 25 dp[k+a[j]][i+1]=1; 26 } 27 } 28 if (dp[l][4]) 29 printf("Yes\n"); 30 else 31 printf("No\n"); 32 } 33 return 0; 34 }
C Adidas vs Adivon
给一张长和宽都是正整数的纸片,每次当前一方可以选择将纸片水平或竖直撕成相等的两半,扔掉一半。但是要求撕完后剩下的那部分纸片长和宽依旧是正整数。直到有一方不能再撕,该方即输掉这场博弈。
看长和宽能除以多少个2,加起来就是能撕的次数,如果次数是奇数是先手胜。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 9 int main() 10 { 11 int cas, n, m, ans; 12 scanf("%d", &cas); 13 while (cas--) { 14 scanf("%d%d", &n, &m); 15 ans=0; 16 while(n%2==0) { 17 ans++; 18 n/=2; 19 } 20 while (m%2==0) { 21 ans++; 22 m/=2; 23 } 24 if (ans&1) printf("Adidas loses\n"); 25 else printf("Adivon prevails\n"); 26 } 27 return 0; 28 }
D 手速为王
给n个单词,每个单词翻转之后再次加入词典,一共就有2n个单词,每次输入一个单词的时候,都要把其他单词输进去,也就是输错2*n-1次,问总共按退格键的次数。
n<=1e5,n个单词的总长度<=1e5
最近软设写的太多,当时一直在想用链表。。
正解是trie树,记录每个节点的使用次数,就是有几个单词用到了这个节点,因为所有没用到这个节点的单词都要删这个节点,并且删除的次数是这个节点的使用次数,所以所有节点的(使用次数*没使用次数)之和就是总退格键数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define ll long long 5 using namespace std; 6 const int maxn = 1000000; 7 int chd[maxn][26], tot; 8 int vis[maxn]; 9 void init() 10 { 11 tot=0; 12 memset(vis, 0, sizeof(vis)); 13 memset(chd[0], 0, sizeof(chd[0])); 14 } 15 void Insert(char* s) 16 { 17 int cur=0, i; 18 for (i=0; s[i]; i++) { 19 if (!chd[cur][s[i]-'a']) { 20 chd[cur][s[i]-'a']=++tot; 21 memset(chd[tot], 0, sizeof(chd[tot])); 22 } 23 cur=chd[cur][s[i]-'a']; 24 vis[cur]++; 25 } 26 cur=0; 27 i--; 28 for (; i>=0; i--) { 29 if (!chd[cur][s[i]-'a']) { 30 chd[cur][s[i]-'a']=++tot; 31 memset(chd[tot], 0, sizeof(chd[tot])); 32 } 33 cur=chd[cur][s[i]-'a']; 34 vis[cur]++; 35 } 36 } 37 char s[100005]; 38 int main() 39 { 40 int cas, n; 41 scanf("%d", &cas); 42 while (cas--) { 43 init(); 44 scanf("%d", &n); 45 for (int i=0; i<n; i++) { 46 scanf(" %s", s); 47 Insert(s); 48 } 49 ll ans=0; 50 for (int i=1; i<=tot; i++) 51 ans+=(ll)(2*n-vis[i])*vis[i]; 52 printf("%lld\n", ans); 53 } 54 return 0; 55 }
F Taiko taiko
太鼓达人简化版,视连续n次击中为n连击,得分为1+2+...+n,例如序列YNNYYYNYN的总分为1+1+2+3+1=8,假设击中概率为P,对于长度为L的序列,求获得积分的期望。L<=1000,最多有1000组数据。
听说这题有规律惊讶
但是我是用DP做的。。
dp[i]表示长度为i的序列得分期望。
对于长度为i的序列,有两种情况,第i位为N,那么是dp[i-1]*q。
假如第i+1位为Y,那么是∑(dp[i-k-1]+sum[k])*p^k*q,也就是枚举最后有多长的连续的Y。sum[k]表示得分,∑sum[k]*p^k*q可以预处理出来。
假设f[i]=∑dp[i-k-1]*p^k*q,满足递推关系f[i]=f[i-1]*p+dp[i-1]*q。
总复杂度是O(n)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 double sum[1005]; 9 double dp[1005]; 10 int main() { 11 int cas; 12 scanf("%d", &cas); 13 int n; 14 double p, tp, q; 15 while (cas--) { 16 scanf("%d%lf", &n, &p); 17 tp=p; q=1-p; 18 //sum[0]=p; 19 for (int i=1; i<=n; i++) { 20 sum[i]=sum[i-1]+i*(i+1)/2*tp; 21 tp*=p; 22 } 23 dp[0]=0; 24 tp=p; 25 double ts=0; 26 for (int i=1; i<=n; i++) { 27 dp[i]=dp[i-1]*q+tp*i*(i+1)/2+sum[i-1]*q+ts*p; 28 ts=ts*p+dp[i-1]*q; 29 tp*=p; 30 } 31 printf("%lf\n", dp[n]); 32 } 33 return 0; 34 }
H 硬币水题II
抛一个硬币,正面朝上的概率为p,反面朝上的概率为1-p。抛两次硬币一正一反称为一个决策,求平均要抛多少次,才能得到一个决策。
找规律。。发现答案就是1/(p*(1-p))
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 10 int main() 11 { 12 int cas; 13 double p; 14 scanf("%d", &cas); 15 while (cas--) { 16 scanf("%lf", &p); 17 printf("%.2lf\n", 1/(p*(1-p))); 18 } 19 return 0; 20 }
I 背包密码
背包密码系统加密过程如下:
选取一个长度为n的正整数超递增序列a[i],满足a[1]<a[2],a[1]+a[2]<a[3],……,a[1]+a[2]+…+a[n-1]<a[n]。
选取正整数m>2*a[n],w和m互质,v是w模m的逆,即(v*w)%m=1。b[i]=(w*a[i])%m。
加密时,对一段长为n的二进制串x[i]。有S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n])%m。
这种密码,告诉你b[i]就可以进行加密。但是仅有b[i]很难进行解密,因为需要求解一个普通的01背包问题 。只有再告诉你v和m,解密就会变得很简单,现在告诉你b[i]、v和m以及S,请你帮忙进行解密。
a数组有很好的性质,假如知道a[1]...a[n]的值和 a[1]*x[1]+a[2]*x[2]+…+a[n]*x[n]的值,就能直接求出x[1]...x[n]的值。
首先因为b[i]=(w*a[i])%m,所以a[i]≡b[i]*v,每次a[i]取最小值,也就是先让a[i]=b[i]*v%m,a[i]+=m,直到a[1]+a[2]+…+a[i-1]<a[i]
为什么是最小值呢?我也不知道。。只是某种直觉。。
把b[i]=w*a[i]%m带入到最后的式子中,得到S=w*(a[1]*x[1]+a[2]*x[2]+...+a[n]*x[n])%m。
a[1]*x[1]+a[2]*x[2]+...+a[n]*x[n]≡S*v,因为m>2*a[n],a[1]*x[1]+a[2]*x[2]+...+a[n]*x[n]肯定是小于m的。
所以a[1]*x[1]+a[2]*x[2]+...+a[n]*x[n]=S*v%m
然后就能把x求出来了
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 int eular(int n) 9 { 10 int ret=1,i; 11 for (i=2;i*i<=n;i++) 12 if (n%i==0) 13 { 14 n/=i,ret*=i-1; 15 while (n%i==0) 16 n/=i,ret*=i; 17 } 18 if (n>1) 19 ret*=n-1; 20 return ret; //n的欧拉数 21 } 22 ll pow_mod(ll a, int b) 23 { 24 if (b==0) return 1; 25 ll ret=a, tmp=a; 26 b--; 27 while (b) { 28 if (b&1) ret*=tmp; 29 tmp*=tmp; 30 b>>=1; 31 } 32 return ret; 33 } 34 ll b[35], a[35]; 35 int x[35]; 36 int main() { 37 int cas; 38 scanf("%d", &cas); 39 int n; 40 ll v, m, s; 41 while (cas--) { 42 scanf("%d", &n); 43 for (int i=0; i<n; i++) 44 scanf("%lld", &b[i]); 45 scanf("%lld%lld%lld", &v, &m, &s); 46 memset(x, 0, sizeof(x)); 47 ll sum=0; 48 for (int i=0; i<n; i++) { 49 a[i]=v*b[i]%m; 50 if (a[i]<=sum) { 51 a[i]+=((sum-a[i])/m+1)*m; 52 } 53 sum+=a[i]; 54 } 55 ll ans=s*v%m; 56 for (int j=n-1; j>=0; j--) { 57 if (ans>=a[j]) { 58 x[j]=1; 59 ans-=a[j]; 60 } 61 } 62 //if (!ans) x[n-1]=1; 63 for (int i=0; i<n; i++) 64 printf("%d", x[i]); 65 puts(""); 66 } 67 return 0; 68 }
J 鸣人的查克拉
鸣人发明了一种忍术,可以在短时间内提高查克拉。
如果在某个时刻发动这个忍术,鸣人需要先消耗该时刻的查克拉值;在某个时候结束这个忍术,鸣人能获得该时刻的查克拉值(忍术必须先发动才能结束)。当然,如果某时刻鸣人具有的查克拉值少于该时刻的查克拉值,那么鸣人是不能发动该忍术的。
由于鸣人对这个忍术还不能很好地控制,所以他最多只能发动两次该忍术,并且两次忍术不能同时发动,也就是说必须结束一次忍术才能发动下一次(第一次结束时可以立即发动第二次)。
现在仪式已经做完了,鸣人知道了自己的查克拉的初始值,以及各个时刻的查克拉值,如果他最多可以发动两次该忍术(他也可以选择发动一次或者不发动),那么他最多能达到的查克拉值是多少?
预处理1-i的最小值,枚举第一次忍术结束的时间。这时候记录在某时刻之前发动一次忍术能得到的最大查克拉值。
从后往前再做一次,就能得到答案。
复杂度O(n)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 int Min[10005], ans[10005], fmax[10005]; 10 int a[10005], amax[10005]; 11 int main() 12 { 13 int n, m, anss=0; 14 scanf("%d%d", &n, &m); 15 for (int i=1; i<=m; i++) { 16 scanf("%d", &a[i]); 17 } 18 Min[0]=inf; fmax[m+1]=amax[0]=0; 19 ans[0]=n; 20 for (int i=1; i<=m; i++) { 21 Min[i]=min(Min[i-1], a[i]); 22 if (Min[i]<=n) { 23 ans[i]=max(ans[i-1], n-Min[i]+a[i]); 24 amax[i]=max(amax[i-1], ans[i]); 25 } 26 else 27 amax[i]=amax[i-1]; 28 } 29 anss=n; 30 for (int i=m; i>=1; i--) { 31 fmax[i]=max(fmax[i+1], a[i]); 32 if (a[i]<=amax[i]) { 33 anss=max(anss, amax[i]-a[i]+fmax[i]); 34 } 35 } 36 printf("%d\n", anss); 37 return 0; 38 }
K PvZ once again
院子是N行M列的,而且种满了大蒜(耐久度K),coming的僵尸只有一只(然而这只僵尸貌似发生了变异,它每啃一口植物,同一列相同种类的植物也被啃掉一口),初始位置在第S行,求僵尸死在1-N号手推车的概率各是多少。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 double f[21][21], dp[21]; 10 struct Matrix 11 { 12 double mat[21][21]; 13 void clear() { 14 for(int i=0; i<21; i++) 15 for (int j=0; j<21; j++) 16 mat[i][j]=0; 17 } 18 friend void operator*=(Matrix &a, Matrix b) 19 { 20 Matrix ret; 21 ret.clear(); 22 for (int i=0; i<21; i++) 23 for (int j=0; j<21; j++) { 24 for (int k=0; k<21; k++) 25 ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j]; 26 } 27 a=ret; 28 } 29 }A, E, ans; 30 Matrix pow_mod(Matrix a, int b) 31 { 32 if (b==0) return E; 33 Matrix ret=a, tmp=a; 34 b--; 35 while (b) { 36 if (b&1) ret*=tmp; 37 tmp*=tmp; 38 b>>=1; 39 } 40 return ret; 41 } 42 void view(Matrix x, int n) 43 { 44 for (int i=1; i<=n; i++){ 45 for (int j=1; j<=n; j++) printf("%lf ", x.mat[i][j]); 46 puts(""); 47 } 48 puts(""); 49 } 50 int main() 51 { 52 int cas, n, m, k, s, f1, f2; 53 scanf("%d", &cas); 54 E.clear(); 55 for (int i=0; i<21; i++) 56 E.mat[i][i]=1; 57 while (cas--) { 58 scanf("%d%d%d%d", &n, &m, &k, &s); 59 if (n==1) { 60 printf("1.0000\n"); 61 continue; 62 } 63 A.clear(); 64 for (int i=2; i<n; i++) { 65 A.mat[i][i+1]=0.5; 66 A.mat[i][i-1]=0.5; 67 } 68 if (n>1) { 69 A.mat[1][2]=1; 70 A.mat[n][n-1]=1; 71 } 72 //view(A, n); 73 //view(pow_mod(A, 2), n); 74 Matrix K; 75 K=pow_mod(A, m*k); 76 for (int i=1; i<n; i++) { 77 printf("%.4lf ", K.mat[s][i]); 78 } 79 printf("%.4lf\n", K.mat[s][n]); 80 } 81 return 0; 82 }
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define ll long long 7 using namespace std; 8 9 int main() { 10 int cas; 11 scanf("%d", &cas); 12 double xl, yl, xr, yr, a, b, c; 13 double y1, y2, x, x1, x2; 14 while (cas--) { 15 scanf("%lf%lf%lf%lf%lf%lf%lf", &xl, &yl, &xr, &yr, &a, &b, &c); 16 if (a&&b) { 17 y1=-(a*xl+c)/b; 18 y2=-(a*xr+c)/b; 19 if (y1>=yl&&y1<=yr) { 20 if (y2>=yl&&y2<=yr) { 21 printf("%.3lf\n", min((xr-xl)*(yr-yl)-(yr-y1+yr-y2)*(xr-xl)/2, (yr-y1+yr-y2)*(xr-xl)/2)); 22 } else { 23 x=-(b*yr+c)/a; 24 if (x<xl) { 25 x=-(b*yl+c)/a; 26 printf("%.3lf\n", (y1-yl)*(x-xl)/2); 27 } else { 28 printf("%.3lf\n", (yr-y1)*(x-xl)/2); 29 } 30 } 31 } else { 32 if (y2>=yl&&y2<=yr) { 33 x=-(b*yr+c)/a; 34 if (x>xr) { 35 x=-(b*yl+c)/a; 36 printf("%.3lf\n", (y2-yl)*(xr-x)/2); 37 } else { 38 printf("%.3lf\n", (yr-y2)*(xr-x)/2); 39 } 40 } else { 41 x1=-(b*yl+c)/a; 42 x2=-(b*yr+c)/a; 43 if (x1>=xl&&x1<=xr) 44 if (x2>=xl&&x2<=xr) 45 printf("%.3lf\n", min((xr-xl)*(yr-yl)-(xr-x1+xr-x2)*(yr-yl)/2, (xr-x1+xr-x2)*(yr-yl)/2)); 46 } 47 } 48 } else if (a) { 49 x=-c/a; 50 printf("%.3lf\n", min(x-xl, xr-x)*(yr-yl)); 51 } else if (b) { 52 y1=-c/b; 53 printf("%.3lf\n", min(y1-yl, yr-y1)*(xr-xl)); 54 } 55 } 56 return 0; 57 }