1001:
题意:
给你13张麻将牌,问可以胡哪些张
思路:
枚举可能接到的牌,然后dfs判断能否胡
1002:
题意:
已知n,m 求 n的所有约数在m进制下的平方和
做法:
队长用java高精度写的
代码:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.PrintWriter; import java.io.ObjectInputStream.GetField; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Scanner; public class Main { static BigInteger getSum(int i, int base){ BigInteger ans= BigInteger.ZERO; BigInteger divider = BigInteger.valueOf(i); String s = divider.toString(base); for (int j = 0; j < s.length(); j++) { BigInteger k = new BigInteger(s.substring(j, j + 1), base); ans = k.multiply(k).add(ans); } return ans; } public static void main(String[] args) { Scanner cin = new Scanner(new BufferedInputStream(System.in)); PrintWriter cout = new PrintWriter(new BufferedOutputStream(System.out)); while (cin.hasNext()) { int n = cin.nextInt(); int base = cin.nextInt(); BigInteger ans = BigInteger.ZERO; for (int i = 1; i * i <= n; i++){ if (n % i == 0) { // i是divider ans = ans.add(getSum(i, base)); if(i*i!=n) ans = ans.add(getSum(n/i, base)); } } cout.println(ans.toString(base).toUpperCase()); } cin.close(); cout.close(); } }
1003:
题意:
给定一串数,每次有三种操作:
1.把当前数加/减1
2.当前数和后面一个数加/减1
3.当前数和后面两个数加/减1
(加减完后的结果是在0~9循环的)
求把当前状态变到目标状态需要的最小操作数
做法:
处理到每个数的时候最多对后面两个数产生影响,因此十进制最多有 10^2=100 种情况,可以全部存下
可以进行dp,dp[i][j]表示前i个数已经达到目标状态 ,第i+1个数和第i+2个数的被操作情况为j(状压一下)的最小操作数,转移只需要枚举三种操作的次数即可
代码:
#include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespace std; #define inf 100000 int mod(int x) { if(x>=0) return x%10; else return (10+x%10)%10; } char s[1010]; char to[1010]; int dp[1010][1010]; int num[3]; int tmp[3]; int p[3]= {1,20,400}; int main() { while(scanf("%s%s",s+1,to+1)!=EOF) { memset(dp,0x3f,sizeof(dp)); dp[0][210]=0; int n=strlen(s+1); for(int i=1; i<=n; i++) { for(int j=1; j<400; j++) { if(dp[i-1][j]>=inf) continue; for(int k=0; k<2; k++) { num[k]=(j%p[k+1])/p[k]; } int cha=mod(to[i]-s[i]-(num[0]-10)); for(int a=0; a<=cha; a++) { for(int b=0; a+b<=cha; b++) { int c=cha-a-b; tmp[0]=num[1]-10+b+c; tmp[0]=tmp[0]%10+10; tmp[1]=c+10; dp[i][tmp[0]+tmp[1]*20]=min(dp[i][tmp[0]+tmp[1]*20],dp[i-1][j]+cha); } } cha=10-cha; for(int a=0; a<=cha; a++) { for(int b=0; a+b<=cha; b++) { int c=cha-a-b; tmp[0]=10-(20-num[1]+b+c)%10; tmp[1]=10-c; dp[i][tmp[0]+tmp[1]*20]=min(dp[i][tmp[0]+tmp[1]*20],dp[i-1][j]+cha); } } } } //printf("%d\n",dp[1][9+9*20]); //printf("%d\n",dp[2][9+10*20]); printf("%d\n",dp[n][210]); } return 0; }
1005:
题意:
一个图有n个点,初始在点1,每次加满油后最多能跑d距离,现在点1有一个加油站,问环游全程回到1需要怎么建加油站
第i点建加油站的话 二进制第i位为1,答案要满足建造情况的二进制数最小
做法:
贪心,要尽量要高位的点不建,先假设所有点建了,再从大到小考虑,如果当前点不建也能满足需求,则把该点加油站删去
因为要考虑连通性所以判断是否满足需求要用bfs
代码:
#include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> #include<queue> #include<math.h> using namespace std; int g[150][150]; int x[150]; int y[150]; int vi[150]; int vis[150]; int n,d; queue<int>q; int check() { memset(vis,0,sizeof(vis)); while(!q.empty()) q.pop(); q.push(0); while(!q.empty()) { int now=q.front(); vis[now]=1; q.pop(); for(int i=0;i<n;i++) { if(!vis[i]) { if(g[now][i]<=d/2) { vis[i]=1; } if(g[now][i]<=d&&vi[i]) { q.push(i); } } } } for(int i=0;i<n;i++) { if(vis[i]==0) return 0; } return 1; } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&d)!=EOF) { for(int i=0;i<n;i++) { vi[i]=1; } for(int i=0; i<n; i++) { scanf("%d%d",x+i,y+i); } for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { g[i][j]=ceil(sqrt((double)((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])))); } } if(check()==0) { puts("-1"); continue; } for(int i=n-1; i>=1; i--) { vi[i]=0; if(!check()) vi[i]=1; } int f=1; for(int i=n-1; i>=0; i--) { if(vi[i]) { printf("1"); f=0; } else { if(f==0) printf("0"); } } puts(""); } return 0; }
1006:
题意: n个字符串,对于每一个子串可以表示为一个数字, 求所有子串的数字和相加对2012取模,, 相同数字只算一次。
这题可以先把n个字符串用一个没有出现过的字符隔开连起来。然后求sa, lcp。
我们可以先看一个简单的例子。
s = 12345
num[1] = 1 sum[1] = 1
num[2] = 12 sum[2] = 1 + 12
num[3] = 123 sum[3] = 1 + 12 + 123
num[4] = 1234 sum[4] = 1 + 12 + 123 + 1234
num[5] = 12345 sum[5] = 1 + 12 + 123 + 1234 + 12345
如果求[3, 4] , 只需要 sum[5] - sum[2] - num[2] * (10 + 100 + 1000);
判重时 只要从 i+ lcp[rank[i]] 开始算就可以了,,因为公共前缀那一部分 在前面已经算了。
上代码。。
1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack> 7 #include <cstdio> 8 #include <string> 9 #include <vector> 10 #include <cstdlib> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 typedef unsigned long long ull; 16 typedef long long ll; 17 const int inf = 0x3f3f3f3f; 18 const double eps = 1e-8; 19 const int mod = 2012; 20 const int maxn = 2e5+100; 21 int sum [maxn], num[maxn]; 22 string s; 23 int sa[maxn], Rank[maxn], tmp[maxn], lcp[maxn]; 24 int k, len; 25 bool cmp(int i, int j) 26 { 27 if (Rank[i] != Rank[j]) 28 return Rank[i] < Rank[j]; 29 else 30 { 31 int x = (i+k <= len ? Rank[i+k] : -1); 32 int y = (j+k <= len ? Rank[j+k] : -1); 33 return x < y; 34 } 35 } 36 void build_sa() 37 { 38 for (int i = 0; i <= len; i++) 39 { 40 sa[i] = i; 41 Rank[i] = (i < len ? s[i] : -1); 42 } 43 for (k = 1; k <= len; k *= 2) 44 { 45 sort (sa,sa+len+1,cmp); 46 tmp[sa[0]] = 0; 47 for (int i = 1; i <= len; i++) 48 { 49 tmp[sa[i]] = tmp[sa[i-1]] + (cmp(sa[i-1],sa[i])? 1 : 0); 50 } 51 for (int i = 0; i <= len; i++) 52 Rank[i] = tmp[i]; 53 } 54 } 55 56 void Get_lcp() 57 { 58 for (int i = 0; i < len; i++) 59 Rank[sa[i]] = i; 60 int h = 0; 61 lcp[0] = 0; 62 for (int i = 0; i < len; i++) 63 { 64 int j = sa[Rank[i]-1]; 65 if (h > 0) 66 h--; 67 for (; h+i < len && h+j < len; h++) 68 if (s[i+h] != s[j+h]) 69 break; 70 lcp[Rank[i]] = h; 71 } 72 } 73 bool isdigit(char &ch) 74 { 75 return ch >= '0' && ch <= '9'; 76 } 77 int vec[maxn], board[maxn], tot; 78 int SUM[maxn]; 79 int solve (int l, int r) 80 { 81 if (l > r) 82 return 0; 83 int res ; 84 res = sum[r] - sum[l-1]; 85 res = ((res%mod)+mod)%mod; 86 res -= num[l-1] * SUM[r-l+1]; 87 res = ((res%mod)+mod)%mod; 88 return ((res%mod)+mod)%mod; 89 } 90 int main() 91 { 92 #ifndef ONLINE_JUDGE 93 freopen("in.txt","r",stdin); 94 #endif 95 int n; 96 SUM[1] = 10; 97 for (int i = 2; i < maxn; i++) 98 { 99 SUM[i] = (SUM[i-1] + 1) * 10 % mod; 100 } 101 while (~scanf ("%d", &n)) 102 { 103 s = "\0"; 104 tot = 0; 105 memset(sum, 0, sizeof(sum)); 106 memset(num, 0, sizeof(num)); 107 for (int i = 0; i < n; i++) 108 { 109 string tmp; 110 cin >> tmp; 111 s += tmp + "#"; 112 } 113 len = s.size(); 114 int val = 0; 115 for (int i = 0; i < len; i++) 116 { 117 if (s[i] != '#') 118 { 119 val = (val * 10 + s[i] - '0') % mod; 120 num[i] = val; 121 sum[i] = (sum[i-1] + num[i]) % mod; 122 board[i] = tot; 123 } 124 if (s[i] == '#') 125 { 126 vec[tot++] = i; 127 num[i] = val; 128 sum[i] = sum[i-1] + val; 129 } 130 } 131 build_sa(); 132 Get_lcp(); 133 int ans = 0; 134 for (int i = 0; i < len; i++) 135 { 136 int t1 = i + lcp[Rank[i]]; 137 if (s[i] == '0') 138 continue; 139 if (isdigit(s[i]) && i+lcp[Rank[i]] < vec[board[i]]) 140 { 141 int t2 = vec[board[i]] -1; 142 int ans1 = solve(i, t2); 143 int ans2 = solve(i , t1-1); 144 ans = (ans + solve(i, t2) - solve(i, t1-1)) % mod; 145 if (ans < 0) 146 ans += mod; 147 } 148 } 149 printf("%d\n", ans%mod); 150 } 151 return 0; 152 }
1008:
题意:
很简单的高中数学签到题
思路:
略
代码:
#include <set> #include <map> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef unsigned long long ull; typedef long long ll; const int inf = 0x3f3f3f3f; const double eps = 1e-8; double x, y; double p, q; double fun1() { double a1 = q*p*p*(x+y); double a2 = q*p*(1-p)*x; double a3 = q*p*(1-p)*y; double a4 = (1-q)*x; return a1+a2+a3+a4; } double fun2() { double a1 = (1-q) * p*p*(x+y); double a2 = (1-q)*p*(1-p)*x; double a3 = (1-q)*p*(1-p)*y; double a4 = (q)*y; return a1+a2+a3+a4;; } int main() { int t; cin>>t; while (t--) { scanf ("%lf%lf%lf%lf",&x, &y, &p, &q); if (fun1() > fun2()) { printf("tiger %.4f\n", fun1()); } else printf("wolf %.4f\n", fun2()); } return 0; }
1011: