偷吃糖果
Time Limit: 1000Ms
Memory Limit: 65536KB
Description
Input
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <stack>
using namespace std;
string remove_duplicates(string s) {
return string(s.begin(), unique(s.begin(), s.end()));
}
int main(){
int T;
cin >> T;
string s,t;
while (T--) {
cin >> s;
s = remove_duplicates(s);
cin >> t;
t = remove_duplicates(t);
if (s.compare(t) == 0){
puts("Yes");
}else {
puts("No");
}
// cout << s << endl << t<< endl;;
}
}
banana
Time Limit: 1000ms
Memory Limit: 65536KB
Input
Sample Input
2 0.0000000000 0.0000000000 -3.0000000000 -3.0000000000 5.0000000000 5.0000000000 6.0000000000 6.0000000000 8.0000000000 8.0000000000 0.0000000000 0.0000000000 -2.0000000000 -2.0000000000 5.0000000000 5.0000000000 6.0000000000 6.0000000000 7.0000000000 7.0000000000
相交的充要条件为:
如果∠BCA’或∠A’BC有一个是钝角,则min(|BA’|, |CA’|) <= |AA’| <= max(|BA’|, |CA’|);
否则,|C’A’| <= |AA’| <= max(|BA’|, |CA’|)
中等想法题
/*======================================================
# Author: whai
# Last modified: 2016-01-09 17:29
# Filename: banana.cpp
======================================================*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <stack>
using namespace std;
#define LL long long
#define PB push_back
#define X first
#define Y second
const double eps = 1e-8;
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) { x = _x; y = _y; }
void scan() {
scanf("%lf%lf", &x, &y);
}
Point operator + (Point a) {
return Point(x + a.x, y + a.y);
}
Point operator - (Point a) {
return Point(x - a.x, y - a.y);
}
double operator * (Point a) {
return x * a.x + y * a.y;
}
double operator ^ (Point a) {
return x * a.y - y * a.x;
}
Point rotate() {
return Point(-y, x);
}
double len() {
return *this * *this;
}
};
Point P, Q;
Point A[1], B[2];
int sgn(double x) {
if (x == 0) return 0;
if (x < 0) return -1;
return 1;
}
double get_min_d(Point O, Point C, Point D) {
double min_d = min((O - C).len(), (O - D).len());
Point OC = C - O;
Point OD = D - O;
Point OH = (D - C).rotate();
if(sgn(OH ^ OC) * sgn(OH ^ OD) != -1) //trick
return min_d;
double s = fabs(OC ^ OD);
double h2 = s * s / (C - D).len();
return h2;
}
bool gao(Point O, Point C, Point D, double R) {
double max_d = max((O - C).len(), (O - D).len());
double min_d = get_min_d(O, C, D);
//cerr<<min_d<<' '<<R<<' '<<max_d<<endl;
if(min_d - eps <= R && R <= max_d + eps)
return true;
return false;
}
int main() {
int T;
cin>>T;
while(T--) {
P.scan(); A[0].scan();
Q.scan(); B[0].scan(); B[1].scan();
Point PQ = Q - P;
double R = PQ.len();
Point O = A[0] + PQ;
bool ans = gao(O, B[0], B[1], R);
if(ans) {
puts("yes");
} else {
//cerr<<P.x<<' '<<P.y<<' '<<A[0].x<<' '<<A[0].y<<endl;
//cerr<<Q.x<<' '<<Q.y<<' '<<B[0].x<<' '<<B[0].y<<' '<<B[1].x<<' '<<B[1].y<<endl;
puts("no");
}
}
return 0;
}
count_prime
Time Limit: 1000ms
Memory Limit: 65536KB
Input
容斥原理、先对n分解质因数,分别记录每个质因数,那么所求区间内与某个质因数不互质的个数就是n/r(i),假设r(i)是r的某个质因子 假设只有三个质因子,总的不互质的个数应该为p1+p2+p3-p1 p2-p1 p3-p2 p3+p1 p2*p3, 及容斥原理,pi代表n/r(i),即与某个质因子不互质的数的个数,当有更多个质因子的时候,可以用状态压缩解决,二进制位上是1表示这个质因子被取进去了。如果有奇数个1就相加,反之则相减。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
int T,cas;
ll a,b,n;
vector<ll> adj;
ll solve(ll x,ll n)
{
adj.clear();
ll i,j;
for (i=2;i*i<=n;i++)
if (n%i==0)
{
adj.push_back(i);
while (n%i==0)
n/=i;
}
if (n>1)
adj.push_back(n);
ll sum=0,value,cnt;
for (i=1;i<(1<<adj.size());i++)
{
value=1;
cnt=0;
for (j=0;j<adj.size();j++)
if (i&(1<<j))
{
value*=adj[j];
cnt++;
}
if (cnt&1)
sum+=x/value;
else
sum-=x/value;
}
return x-sum;
}
int main()
{
//cas=0;
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld%lld",&a,&b,&n);
printf("%lld\n",solve(b,n)-solve(a-1,n));
}
return 0;
}
triple
Time Limit: 3000MS
Memory Limit: 65536KB
Description
简单的莫比乌斯反演
令f(d)表示x,y,z的gcd=d的个数
则F(d)表示x,y,z的gcd是d的倍数的个数
/*======================================================
# Author: whai
# Last modified: 2016-01-11 13:13
# Filename: triple.cpp
======================================================*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <stack>
using namespace std;
#define LL long long
#define PB push_back
#define P pair<int, int>
#define X first
#define Y second
const int N = 1e5 + 5;
int mu[N];
void getMu() {
for (int i = 1; i < N; ++i) {
int target = i == 1 ? 1 : 0;
int delta = target - mu[i];
mu[i] = delta;
for (int j = 2 * i; j < N; j += i)
mu[j] += delta;
}
}
int cnt[N];
void deal(int x) {
for(int i = 1; i * i <= x; ++i) {
if(x % i == 0) {
++cnt[i];
int tmp = x / i;
if(tmp != i) {
++cnt[tmp];
}
}
}
}
LL F(int x) {
LL tmp = cnt[x];
if(tmp < 3) return 0;
return tmp * (tmp - 1) * (tmp - 2) / 6;
}
void gao(int n, int m) {
LL ans = 0;
for(int i = 1; i * m < N; ++i) {
ans += mu[i] * F(i * m);
}
cout<<ans<<endl;
}
void init() {
memset(cnt, 0, sizeof(cnt));
}
int main() {
getMu();
int T;
scanf("%d", &T);
while(T--) {
int n, m;
scanf("%d%d", &n, &m);
init();
for(int i = 1; i <= n; ++i) {
deal(i);
}
gao(n, m);
}
return 0;
}
sad
Time Limit: 8000MS
Memory Limit: 65536KB
Description
Input
三个条件一个一个干
对于第一个和第二个条件,其实就是说有一些组必须在一起
那我们就让他们在一起(在一起!在一起!)。。。。
因为他要求每一对都要满足fi, ci所以搞一个最大值的后缀就好了。。。
具体见标程reset函数
然后就是第三个条件和最后要求的东西
显然直觉上二分,二分答案S
然后题目就变成了,所有分组的的最大值的和需要尽量小ANS。
并且在这个尽量小的情况下,判断一下ANS和limit的大小
logn
最后,那么得到 【所有分组的最大值的和的最小值】 呢?
显然DP,并且DP答案是单调上升的,然后单调队列优化。
由于过程中有删除插入操作所以上multiset。当然你可以手敲平衡树。
具体就是:
设DP[i]为,当到i为止的 【分组的最大值的和的最小值】。
那么有: dp[i] = min(dp[j] + max(C[j+1], ..., C[i])) (j<i) 然后因为有二分出的答案金钱的限制,所以j也有限制,先假设这里 j >= head
而 F[head-1] + F[head] + F[head+1] + ... + F[i] > S (我们二分的答案金钱上限)
对于head ~ i因为每一个DP要求的是区段的最大值,所以我们维护一个递减的队列q,
记录一个递减的ci
c[q[l]] > c[q[l+1]] > ....c[q[r]]
而任何在head ~ i之间的dp[j] + max(xx)这个max(xx)都在这个序列中。
显然这时候,因为dp[i]是一个递增的序列,所以对于每一个q[i],总是与尽量前面的dp[i]合体,能得带更小的值。
dp[i] = min(c[q[l]] + dp[head-1],
c[q[l+1]] + dp[que[l]], c[q[l+2]] + dp[que[l+1]], ..., c[que[r]]+dp[que[r-1]]) ;
而这个东西用set维护,与队列共存
nlogn
总复杂度 n(logn)(logn)
#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>
#include <set>
// #include <ctime>
using namespace std;
const int maxn = 1e5+5;
const int inf = 1e9+7;
int n, limit;
int c[maxn], f[maxn];
void reset(){
static int c_max[maxn], cc[maxn], ff[maxn];
c_max[n+1] = -1;
for(int i=n;i>=1;i--)
c_max[i] = max(c[i], c_max[i+1]);
int nn = 0, f_min = inf, st = 1;
for(int i=1;i<=n;i++){
f_min = min(f_min, f[i]);
if ( f_min > c_max[i+1] || i==n ){
nn++; cc[nn] = 0, ff[nn] = 0;
for(int j=st;j<=i;j++){
cc[nn] = max(cc[nn], c[j]);
ff[nn] += f[j];
}
st = i+1; f_min = inf;
}
}
n = nn;
for(int i=1;i<=n;i++)
c[i] = cc[i], f[i] = ff[i];
}
bool test(int s){
static int dp[maxn];
static int que[maxn], l, r;
static multiset<int> myset;
for(int i=1;i<=n;i++)
if ( f[i]>s ) return false;
r = 0, l = 1; myset.clear();
int sumf = 0, head = 1; dp[0] = 0;
for(int i=1;i<=n;i++){
sumf += f[i];
// ->
while ( head<i && sumf>s ) {
sumf -= f[head++];
}
// <-
while ( l<=r && c[que[r]]<=c[i] ){
if ( l<r )
myset.erase( dp[que[r-1]] + c[que[r]] );
r--;
}
if( l<=r )
myset.insert( dp[que[r]] + c[i] );
que[++r] = i;
// ->
while ( l<=r && que[l]<head ){
if ( l<r )
myset.erase( dp[que[l]] + c[que[l+1]] );
l++;
}
dp[i] = dp[head-1] + c[ que[l] ];
if ( !myset.empty() )
dp[i] = min(dp[i], *myset.begin() );
}
return dp[n] <= limit ;
}
int main(){
// double st = clock();
while ( scanf("%d%d", &n, &limit)!=EOF ){
for(int i=1;i<=n;i++)
scanf( "%d%d", &c[i], &f[i] );
if ( n==0 ){
puts("0"); continue;
}
reset();
int l = 1, r = 0, mid;
for(int i=1;i<=n;i++) r += f[i];
while ( l<r-1 ){
mid = (l+r)>>1;
if ( test(mid) ) r = mid;
else l = mid;
}
if ( test(r) ) mid = r;
else if ( test(l) ) mid = l;
else mid = -1;
printf("%d\n", mid);
}
// double en = clock();
// cerr<<(en - st) / CLOCKS_PER_SEC<<endl;
return 0;
}
sequence
Time Limit: 1000MS
Memory Limit: 65536KB
Description
Input
经典贪心问题,从前往后扫描原数组,每到一个数,找个当前最大值最大的不降数组加入其中,否则新建一个不降数组。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
int height[10000];
int main()
{
int T;cin>>T;
while(T--)
{
int n;cin>>n;
int number;
int index = 0;
while(n--)
{
scanf("%d",&number);
int tmp_index = -1;
for (int i = 0; i < index; ++i)
{
if(number>=height[i] && (tmp_index == -1 || height[tmp_index] < height[i]))
{
tmp_index = i;
}
}
if(tmp_index != -1)
{
height[tmp_index] = number;
}
else height[index++] = number;
}
cout<<index<<endl;
}
}
琪露诺的算术教室
Time Limit: 1000ms
Memory Limit: 65536KB
Description
首先,从最后一位开始,依次 k,注意进位,就可以很快的找到模拟的思路。
然后,从尾数范围10 进位范围10 = 100可知。答案应该是循环的,我们用vis数组标记即可。
最后有三个错的比较多的地方:
1.B的次高位不能是0,也就说A的最高位不能是0.
2.循环什么时候结束,需要仔细斟酌一下.
3.n=0的情况,n=1的情况,和k=0的情况 请仔细考虑。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int ans[1005];
bool vis[10][10];
int n,k;
int main(){
int cases;
scanf("%d",&cases);
for (int cas=1;cas<=cases;cas++){
scanf("%d%d",&n,&k);
memset(ans,0,sizeof(ans));
int top=0;
int x=n*k %10;
int y=n*k /10;
y+=(ans[top]+x)/10;
x=(ans[top]+x)%10;
//cout<<n<<'+'<<k<<endl;
memset(vis,false,sizeof(vis));
bool flag=true;
while (y!=0 || x!=n || (top>0 && ans[top-1]==0)){
ans[top]=x;
ans[top+1]=y;
if (vis[ans[top]][y]){
flag=false;
break;
}
vis[ans[top]][y]=true;
x=ans[top]*k %10;
y=ans[top]*k /10;
top++;
y+=(ans[top]+x)/10;
x=(ans[top]+x)%10;
}
ans[top]=x;
ans[top+1]=y;
top++;
if (!flag){
puts("-1");
continue;
}
for (int i=top-1;i>=0;i--)
printf("%d",ans[i]);
putchar('\n');
}
return 0;
}
谁才是最强战舰!
Time Limit: 1000MS
Memory Limit: 65536KB
Description
Input
奇异局势,所有堆xor和==0.
假定S是非奇异局势,T是奇异局势。
一堆中石子数量>=2,表示充裕堆, =1表示孤单堆。
S0即非奇异局势下,充裕堆为0的状态
S1即非奇异局势下,充裕堆为1的状态
S2即非奇异局势下,充裕堆>=2的状态
T0即奇异局势下,充裕堆为0的状态
T2即奇异局势下,充裕堆>=2的状态
1.奇异局势的定义可知,S能转移到T,能转移到S, T只能转移到S
2.S0必败,T0必胜
3.S1必胜,因为S1只需要转移到S0即可。
4.S2必胜,T2必败。
1)T2只能转移到S1 和 S2
2)若T2转移到S1 则T2败,若T2转移到S2,S2只需要转回到T2即可。所以S2胜,T2败。
所以:
必胜态:T0,S1,S2
必败态:S0,T2
//必胜:T0,S1,S2
//必败:S0,T2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int main(){
int cases;
scanf("%d",&cases);
for (int cas=1;cas<=cases;cas++){
int n; scanf("%d",&n);
int sum=0,ones=0;
for (int i=1;i<=n;i++){
int x; scanf("%d",&x);
sum^=x;
if (x==1) ones++;
}
if (sum==0){
if (n-ones==0) puts("Yamato_Saikou!");
else puts("Meidikeji_Shijiediyi!");
}
else {
if (n-ones==0){
if (ones&1) puts("Meidikeji_Shijiediyi!");
//必定是奇数堆,非奇异局势
}
else puts("Yamato_Saikou!");
}
}
return 0;
}
puzzle
Time Limit: 1000MS
Memory Limit: 65536KB
Description
Input
首先二分一下可以闯过的关卡数,然后2sat建模就好
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <assert.h>
using namespace std;
const int MAXN = 10000;
int n, m;
struct note
{
int u, v, c;
note() {}
note(int u, int v, int c): u(u), v(v), c(c) {}
} p[MAXN];
int head[MAXN];
int next_[MAXN];
int dfn[MAXN];
int low[MAXN];
int instack[MAXN];
int belong[MAXN];
stack<int> sta;
int e = 0;
int indexx;
int cnt = 0;
int x[MAXN];
int y[MAXN];
void addnote(int u, int v, int c)
{
p[e] = note(u, v, c);
next_[e] = head[u];
head[u] = e++;
}
void init()
{
for (int i = 0; i < MAXN; ++i)
{
head[i] = next_[i] = -1;
}
while(!sta.empty()) sta.pop();
memset(p, 0, sizeof(p));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(belong, 0, sizeof(belong));
memset(instack, 0, sizeof(instack));
e = 0;
cnt = 0;
indexx = 0;
}
void tarjan(int u)
{
//assert(u!=2*m);
dfn[u] = low[u] = ++indexx;
instack[u] = 1;
sta.push(u);
for (int i = head[u]; i != -1; i = next_[i])
{
int v = p[i].v;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u])
{
int v;
cnt++;
do
{
v = sta.top();
sta.pop();
instack[v] = 0;
belong[v] = cnt;
} while (u != v);
}
}
void solve()
{
for (int i = 0; i < 2 * m; i++)
if (!dfn[i])
tarjan(i);
}
int main()
{
int T; cin >> T;
while (T--)
{
cin >> m;
for (int i = 0; i < m; ++i)
{
scanf("%d %d", &x[i], &y[i]);
}
int lower = 0, upper = m;
while (lower <= upper)
{
init();
//cout<<"----------"<<endl;
int mid = (lower + upper) >> 1;
for (int i = 0; i < mid; ++i)
{
//printf("addnote(%d,%d)\n", 2 * n - 1 - x[i],y[i]);
//printf("addnote(%d,%d)\n", 2 * n - 1 - y[i],x[i]);
addnote(2 * m - 1 - x[i], y[i],1);
addnote(2 * m - 1 - y[i], x[i],1);
}
solve();
bool flag = true;
for (int i = 0; i < m && flag; ++i)
{
//printf("belong[%d]=%d;belong[%d]=%d;\n",i,belong[i],2 * m - 1 - i,belong[2 * m - 1 - i]);
if (belong[i] == belong[2 * m - 1 - i])
{
flag = false;
}
}
if (flag) lower = mid + 1;
else upper = mid - 1;
//cout<<"----------"<<endl;
}
cout<<(lower+upper)/2<<endl;
}
return 0;
}
water1
Time Limit: 1000MS
Memory Limit: 65536KB
Description
Input
找一个最高点h、、
答案就是
(h+1)*sum(wi) - 各海拔
#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>
#define LL long long
using namespace std;
const int maxn = 1e5+5;
int n;
int h[maxn],w[maxn];
int main(){
while ( scanf("%d",&n)!=EOF ){
if ( n==0 ){
puts("1");
continue;
}
int maxh = -1;
for(int i=1;i<=n;i++){
scanf("%d%d", &h[i], &w[i]);
maxh = max(maxh, h[i]);
}
LL ans = 0;
for(int i=1;i<=n;i++)
ans += (LL)w[i] * (maxh+1 - h[i]);
printf("%lld\n", ans);
}
return 0;
}