BestCoder Round #41------>
现在才补上,主要是第三题看到神奇代码:
A:只能说真的好题,我写的很复杂,开始的时候没发现其实可以改变相对顺序,结果。。。
思路(请忽视代码吧!写的太乱,另外模拟题一直是我最大的不足
有5个,如果我们全排列所有的话,生成5!=120中,
对一种判断的方法是固定一个数,我们可以生成合法序列的一种,然后跟原来数列对比。
这里还要考虑10 11 12 13 1这种排列方式。找到最优解。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<string.h> 5 #include<string> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<vector> 10 11 #define N 123456 12 #define inf 0x3f3f3f 13 using namespace std; 14 typedef long long ll; 15 16 17 string ss[5]; 18 19 int a[6]; 20 int b[6]; 21 22 23 int main() 24 { 25 int T; 26 scanf("%d",&T); 27 28 while (T--) 29 { 30 for (int i=0;i<5;i++) cin>>ss[i]; 31 int sxbk=123; 32 sort(ss,ss+5); 33 34 do 35 { 36 for (int i=0;i<5;i++) 37 { 38 if (ss[i][0]=='A') a[i]=100; 39 else if (ss[i][0]=='B') a[i]=200; 40 else if (ss[i][0]=='C') a[i]=300; 41 else if (ss[i][0]=='D') a[i]=400; 42 int m=ss[i].size(); 43 44 if (m==2) a[i]+=ss[i][1]-'0'; 45 else a[i]+=(ss[i][1]-'0')*10+ss[i][2]-'0'; 46 } 47 48 for (int i=0;i<5;i++) 49 { 50 b[i]=a[i]%100; 51 int wei=a[i]/100; 52 for (int j=i-1;j>=0;j--) 53 { 54 b[j]=b[i]-1; 55 if (b[j]==0) b[j]=1; 56 } 57 58 for (int j=i+1;j<5;j++) 59 { 60 b[j]=b[j-1]+1; 61 if (b[j]==14) b[j]=1; 62 } 63 64 int flag=0; 65 for (int j=0;j<5;j++) 66 { 67 if (b[j]==13&&j<3) flag=1; 68 if (b[j]==1&&!(j==0||j==4) ) flag=1; 69 } 70 71 72 if (flag) continue; 73 74 int tmp=0; 75 for (int j=0;j<5;j++) { 76 b[j]+=wei*100; 77 if (a[j]!=b[j]) tmp++; 78 } 79 sxbk=min(sxbk,tmp); 80 } 81 } while (next_permutation(ss,ss+5)); 82 printf("%d\n",sxbk); 83 } 84 return 0; 85 }
B,写下A题没多少时间了,忘记考虑字串相等也是输的情况。
所以就是简单的判断奇数偶数,然后用map 判断有多少个完全相等的字串
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<string.h> 5 #include<string> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<vector> 10 11 #define N 123456 12 #define inf 0x3f3f3f 13 using namespace std; 14 typedef long long ll; 15 16 int a[23456]; 17 18 map<string,int>mp; 19 string ss; 20 21 int gcd(int aa,int bb) 22 { 23 if (aa==0) return 1; 24 if (bb==0) return aa; 25 return gcd(bb,aa%bb); 26 } 27 28 29 int main() 30 { 31 int T; 32 scanf("%d",&T); 33 while (T--) 34 { 35 int n; 36 scanf("%d",&n); 37 mp.clear(); 38 39 int jishu,ou; 40 jishu=ou=0; 41 42 for (int i=1;i<=n;i++) 43 { 44 cin>>ss; 45 a[i]=ss.size(); 46 if (a[i]&1) jishu ++; 47 else ou++; 48 mp[ss]++; 49 } 50 51 int xx=n*(n-1)/2; 52 53 int yy=jishu*ou; 54 55 map<string,int>::iterator it; 56 for ( it=mp.begin();it!=mp.end();it++){ 57 int tmp=it->second; 58 yy+=tmp*(tmp-1)/2; 59 } 60 61 62 int tt=gcd(yy,xx); 63 // if (yy==0) tt=1,xx=1; 64 65 printf("%d/%d\n",yy/tt,xx/tt); 66 } 67 return 0; 68 }
C:
------------------------------------------分----------------------------------------------隔--------------------------------------线
这道题赛后补了好久,不能跟上代码的思维度了。
先丢AC代码:
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<cmath> 5 #include<string> 6 #include<vector> 7 #include<stdio.h> 8 9 using namespace std; 10 11 typedef long long LL; 12 typedef double DB; 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 const int MX = 100005; 16 17 const int MC = 450; 18 const int MOD = 998244353; 19 int f[MX], g[MX]; 20 int *p = f, *q = g; 21 int s[MX]; 22 23 void init() { 24 int i, j; 25 p[0] = 1; 26 27 for (i = 1; i < MC; i++) { 28 for (j = 0; j < MX; j++) s[j] = (s[j] + p[j]) % MOD; 29 for (j = 0; j < i; j++) q[j] = 0; 30 for (j = i; j < MX; j++) q[j] = (p[j - i] + q[j - i]) % MOD; 31 swap(p, q); 32 } 33 34 for (j = 1; j < MX; j++) s[j] = (s[j] + s[j - 1]) % MOD; 35 } 36 37 int main() { 38 39 int tc, n, c, st, en, rlt; 40 41 init(); 42 for (scanf("%d", &tc); tc--; ) { 43 scanf("%d%d%d%d", &n, &c, &st, &en); 44 rlt = s[en - c]; 45 cout<<s[en-c]<<" "<<s[st-c]<<endl; 46 if (st > c) rlt = (rlt + MOD - s[st - c - 1]) % MOD; 47 // printf("%d\n", rlt); 48 } 49 return 0; 50 }
然后是我转换DP方程的代码:
1 #include <iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<math.h> 5 6 using namespace std; 7 const int MC=448; 8 const int MX=100001; 9 const int MOD= 998244353; 10 11 int s[MX]; 12 int dp[MC][MX];//表示 用多少个数,构成和为MX 的方案数 13 14 void init() 15 { 16 dp[0][0]=1; 17 18 19 20 for (int i=1;i<MC;i++) { 21 for (int j=0;j<MX;j++) s[j]=(s[j]+dp[i-1][j])%MOD;//s[j]表示组成和为j的方案数,不管有多少个数。 22 for (int j=i;j<MX;j++) dp[i][j]=(dp[i][j-i]+dp[i-1][j-i])%MOD;// 太神奇这里这个方程 23 //这个转移方程的意思是:类似01背包,dp[i-1][j-i]表示再加入i这个points,dp[i][j-i]表示不懂 24 //可能表示一种转移即dp[i][j-i]的方案同样可以构成dp[i][j]. 25 //希望这里能有解释一下。
//BC题解有:
//转移的时候,要么把之前选择的每一个数增加一,要么在把之前选择的每一个数都增加一个基础上,再新加入一个当前大小为1的数。
26 } 27 28 for (int j=1;j<MX;j++) s[j]=(s[j]+s[j-1])%MOD;//前缀和,s[i]表示构成1-i所有的方案数 29 } 30 31 int main() 32 { 33 int T; 34 scanf("%d",&T); 35 init(); 36 while (T--) 37 { 38 int n,c,l,r; 39 scanf("%d%d%d%d",&n,&c,&l,&r); 40 int ans=s[r-c]; 41 42 if (l>c) ans=(ans+MOD-s[l-c-1])%MOD; 43 printf("%d\n",ans); 44 } 45 return 0; 46 }
本来第二个代码也可以O(nsqrt(n)),但是爆了空间,必须剩下空间。
思路:都是先预处理出S【I】表示生成1-i所有的方案数。
然后减减就可以了。
INIT部分;在代码中,希望能解释代码中我的疑问,
随性Code